// SPDX-License-Identifier: MIT
/*
* Copyright © 2023 - 2025 Intel Corporation
*/
#include "abi/guc_relay_actions_abi.h"
#include "xe_device_types.h"
#include "xe_sriov.h"
#include "xe_sriov_pf_helpers.h"
#include "xe_sriov_printk.h"
#include "xe_sriov_pf_service.h"
#include "xe_sriov_pf_service_types.h"
/**
* xe_sriov_pf_service_init - Early initialization of the SR - IOV PF service .
* @ xe : the & xe_device to initialize
*
* Performs early initialization of the SR - IOV PF service .
*
* This function can only be called on PF .
*/
void xe_sriov_pf_service_init(struct xe_device *xe)
{
BUILD_BUG_ON(!GUC_RELAY_VERSION_BASE_MAJOR && !GUC_RELAY_VERSION_BASE_MINOR);
BUILD_BUG_ON(GUC_RELAY_VERSION_BASE_MAJOR > GUC_RELAY_VERSION_LATEST_MAJOR);
xe_assert(xe, IS_SRIOV_PF(xe));
/* base versions may differ between platforms */
xe->sriov.pf.service.version.base.major = GUC_RELAY_VERSION_BASE_MAJOR;
xe->sriov.pf.service.version.base.minor = GUC_RELAY_VERSION_BASE_MINOR;
/* latest version is same for all platforms */
xe->sriov.pf.service.version.latest.major = GUC_RELAY_VERSION_LATEST_MAJOR;
xe->sriov.pf.service.version.latest.minor = GUC_RELAY_VERSION_LATEST_MINOR;
}
/* Return: 0 on success or a negative error code on failure. */
static int pf_negotiate_version(struct xe_device *xe,
u32 wanted_major, u32 wanted_minor,
u32 *major, u32 *minor)
{
struct xe_sriov_pf_service_version base = xe->sriov.pf.service.version.base;
struct xe_sriov_pf_service_version latest = xe->sriov.pf.service.version.latest;
xe_assert(xe, IS_SRIOV_PF(xe));
xe_assert(xe, base.major);
xe_assert(xe, base.major <= latest.major);
xe_assert(xe, (base.major < latest.major) || (base.minor <= latest.minor));
/* VF doesn't care - return our latest */
if (wanted_major == VF2PF_HANDSHAKE_MAJOR_ANY &&
wanted_minor == VF2PF_HANDSHAKE_MINOR_ANY) {
*major = latest.major;
*minor = latest.minor;
return 0 ;
}
/* VF wants newer than our - return our latest */
if (wanted_major > latest.major) {
*major = latest.major;
*minor = latest.minor;
return 0 ;
}
/* VF wants older than min required - reject */
if (wanted_major < base.major ||
(wanted_major == base.major && wanted_minor < base.minor)) {
return -EPERM;
}
/* previous major - return wanted, as we should still support it */
if (wanted_major < latest.major) {
/* XXX: we are not prepared for multi-versions yet */
xe_assert(xe, base.major == latest.major);
return -ENOPKG;
}
/* same major - return common minor */
*major = wanted_major;
*minor = min_t(u32, latest.minor, wanted_minor);
return 0 ;
}
static void pf_connect(struct xe_device *xe, u32 vfid, u32 major, u32 minor)
{
xe_sriov_pf_assert_vfid(xe, vfid);
xe_assert(xe, major || minor);
xe->sriov.pf.vfs[vfid].version.major = major;
xe->sriov.pf.vfs[vfid].version.minor = minor;
}
static void pf_disconnect(struct xe_device *xe, u32 vfid)
{
xe_sriov_pf_assert_vfid(xe, vfid);
xe->sriov.pf.vfs[vfid].version.major = 0 ;
xe->sriov.pf.vfs[vfid].version.minor = 0 ;
}
/**
* xe_sriov_pf_service_is_negotiated - Check if VF has negotiated given ABI version .
* @ xe : the & xe_device
* @ vfid : the VF identifier
* @ major : the major version to check
* @ minor : the minor version to check
*
* Performs early initialization of the SR - IOV PF service .
*
* This function can only be called on PF .
*
* Returns : true if VF can use given ABI version functionality .
*/
bool xe_sriov_pf_service_is_negotiated(struct xe_device *xe, u32 vfid, u32 major, u32 minor)
{
xe_sriov_pf_assert_vfid(xe, vfid);
return major == xe->sriov.pf.vfs[vfid].version.major &&
minor <= xe->sriov.pf.vfs[vfid].version.minor;
}
/**
* xe_sriov_pf_service_handshake_vf - Confirm a connection with the VF .
* @ xe : the & xe_device
* @ vfid : the VF identifier
* @ wanted_major : the major service version expected by the VF
* @ wanted_minor : the minor service version expected by the VF
* @ major : the major service version to be used by the VF
* @ minor : the minor service version to be used by the VF
*
* Negotiate a VF / PF ABI version to allow VF use the PF services .
*
* This function can only be called on PF .
*
* Return : 0 on success or a negative error code on failure .
*/
int xe_sriov_pf_service_handshake_vf(struct xe_device *xe, u32 vfid,
u32 wanted_major, u32 wanted_minor,
u32 *major, u32 *minor)
{
int err;
xe_sriov_dbg_verbose(xe, "VF%u wants ABI version %u.%u\n" ,
vfid, wanted_major, wanted_minor);
err = pf_negotiate_version(xe, wanted_major, wanted_minor, major, minor);
if (err < 0 ) {
xe_sriov_notice(xe, "VF%u failed to negotiate ABI %u.%u (%pe)\n" ,
vfid, wanted_major, wanted_minor, ERR_PTR(err));
pf_disconnect(xe, vfid);
} else {
xe_sriov_dbg(xe, "VF%u negotiated ABI version %u.%u\n" ,
vfid, *major, *minor);
pf_connect(xe, vfid, *major, *minor);
}
return err;
}
/**
* xe_sriov_pf_service_reset_vf - Reset a connection with the VF .
* @ xe : the & xe_device
* @ vfid : the VF identifier
*
* Reset a VF driver negotiated VF / PF ABI version .
*
* After that point , the VF driver will have to perform new version handshake
* to continue use of the PF services again .
*
* This function can only be called on PF .
*/
void xe_sriov_pf_service_reset_vf(struct xe_device *xe, unsigned int vfid)
{
pf_disconnect(xe, vfid);
}
static void print_pf_version(struct drm_printer *p, const char *name,
const struct xe_sriov_pf_service_version *version)
{
drm_printf(p, "%s:\t%u.%u\n" , name, version->major, version->minor);
}
/**
* xe_sriov_pf_service_print_versions - Print ABI versions negotiated with VFs .
* @ xe : the & xe_device
* @ p : the & drm_printer
*
* This function is for PF use only .
*/
void xe_sriov_pf_service_print_versions(struct xe_device *xe, struct drm_printer *p)
{
unsigned int n, total_vfs = xe_sriov_pf_get_totalvfs(xe);
struct xe_sriov_pf_service_version *version;
char name[8 ];
xe_assert(xe, IS_SRIOV_PF(xe));
print_pf_version(p, "base" , &xe->sriov.pf.service.version.base);
print_pf_version(p, "latest" , &xe->sriov.pf.service.version.latest);
for (n = 1 ; n <= total_vfs; n++) {
version = &xe->sriov.pf.vfs[n].version;
if (!version->major && !version->minor)
continue ;
print_pf_version(p, xe_sriov_function_name(n, name, sizeof (name)), version);
}
}
#if IS_BUILTIN(CONFIG_DRM_XE_KUNIT_TEST)
#include "tests/xe_sriov_pf_service_kunit.c"
#endif
Messung V0.5 in Prozent C=93 H=97 G=94
¤ Dauer der Verarbeitung: 0.20 Sekunden
(vorverarbeitet am 2026-10-11)
¤
*© Formatika GbR, Deutschland