551 lines
16 KiB
C
551 lines
16 KiB
C
// SPDX-License-Identifier: MIT
|
|
/*
|
|
* Copyright © 2023-2024 Intel Corporation
|
|
*/
|
|
|
|
#include <drm/drm_managed.h>
|
|
|
|
#include "abi/guc_actions_sriov_abi.h"
|
|
#include "abi/guc_relay_actions_abi.h"
|
|
|
|
#include "regs/xe_gt_regs.h"
|
|
#include "regs/xe_guc_regs.h"
|
|
#include "regs/xe_regs.h"
|
|
|
|
#include "xe_mmio.h"
|
|
#include "xe_gt_sriov_printk.h"
|
|
#include "xe_gt_sriov_pf_helpers.h"
|
|
#include "xe_gt_sriov_pf_service.h"
|
|
#include "xe_gt_sriov_pf_service_types.h"
|
|
#include "xe_guc_ct.h"
|
|
#include "xe_guc_hxg_helpers.h"
|
|
|
|
static void pf_init_versions(struct xe_gt *gt)
|
|
{
|
|
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);
|
|
|
|
/* base versions may differ between platforms */
|
|
gt->sriov.pf.service.version.base.major = GUC_RELAY_VERSION_BASE_MAJOR;
|
|
gt->sriov.pf.service.version.base.minor = GUC_RELAY_VERSION_BASE_MINOR;
|
|
|
|
/* latest version is same for all platforms */
|
|
gt->sriov.pf.service.version.latest.major = GUC_RELAY_VERSION_LATEST_MAJOR;
|
|
gt->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_gt *gt,
|
|
u32 wanted_major, u32 wanted_minor,
|
|
u32 *major, u32 *minor)
|
|
{
|
|
struct xe_gt_sriov_pf_service_version base = gt->sriov.pf.service.version.base;
|
|
struct xe_gt_sriov_pf_service_version latest = gt->sriov.pf.service.version.latest;
|
|
|
|
xe_gt_assert(gt, base.major);
|
|
xe_gt_assert(gt, base.major <= latest.major);
|
|
xe_gt_assert(gt, (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_gt_assert(gt, 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_gt *gt, u32 vfid, u32 major, u32 minor)
|
|
{
|
|
xe_gt_sriov_pf_assert_vfid(gt, vfid);
|
|
xe_gt_assert(gt, major || minor);
|
|
|
|
gt->sriov.pf.vfs[vfid].version.major = major;
|
|
gt->sriov.pf.vfs[vfid].version.minor = minor;
|
|
}
|
|
|
|
static void pf_disconnect(struct xe_gt *gt, u32 vfid)
|
|
{
|
|
xe_gt_sriov_pf_assert_vfid(gt, vfid);
|
|
|
|
gt->sriov.pf.vfs[vfid].version.major = 0;
|
|
gt->sriov.pf.vfs[vfid].version.minor = 0;
|
|
}
|
|
|
|
static bool pf_is_negotiated(struct xe_gt *gt, u32 vfid, u32 major, u32 minor)
|
|
{
|
|
xe_gt_sriov_pf_assert_vfid(gt, vfid);
|
|
|
|
return major == gt->sriov.pf.vfs[vfid].version.major &&
|
|
minor <= gt->sriov.pf.vfs[vfid].version.minor;
|
|
}
|
|
|
|
static const struct xe_reg tgl_runtime_regs[] = {
|
|
RPM_CONFIG0, /* _MMIO(0x0d00) */
|
|
MIRROR_FUSE3, /* _MMIO(0x9118) */
|
|
XELP_EU_ENABLE, /* _MMIO(0x9134) */
|
|
XELP_GT_SLICE_ENABLE, /* _MMIO(0x9138) */
|
|
XELP_GT_GEOMETRY_DSS_ENABLE, /* _MMIO(0x913c) */
|
|
GT_VEBOX_VDBOX_DISABLE, /* _MMIO(0x9140) */
|
|
CTC_MODE, /* _MMIO(0xa26c) */
|
|
HUC_KERNEL_LOAD_INFO, /* _MMIO(0xc1dc) */
|
|
TIMESTAMP_OVERRIDE, /* _MMIO(0x44074) */
|
|
};
|
|
|
|
static const struct xe_reg ats_m_runtime_regs[] = {
|
|
RPM_CONFIG0, /* _MMIO(0x0d00) */
|
|
MIRROR_FUSE3, /* _MMIO(0x9118) */
|
|
MIRROR_FUSE1, /* _MMIO(0x911c) */
|
|
XELP_EU_ENABLE, /* _MMIO(0x9134) */
|
|
XELP_GT_GEOMETRY_DSS_ENABLE, /* _MMIO(0x913c) */
|
|
GT_VEBOX_VDBOX_DISABLE, /* _MMIO(0x9140) */
|
|
XEHP_GT_COMPUTE_DSS_ENABLE, /* _MMIO(0x9144) */
|
|
CTC_MODE, /* _MMIO(0xa26c) */
|
|
HUC_KERNEL_LOAD_INFO, /* _MMIO(0xc1dc) */
|
|
TIMESTAMP_OVERRIDE, /* _MMIO(0x44074) */
|
|
};
|
|
|
|
static const struct xe_reg pvc_runtime_regs[] = {
|
|
RPM_CONFIG0, /* _MMIO(0x0d00) */
|
|
MIRROR_FUSE3, /* _MMIO(0x9118) */
|
|
XELP_EU_ENABLE, /* _MMIO(0x9134) */
|
|
XELP_GT_GEOMETRY_DSS_ENABLE, /* _MMIO(0x913c) */
|
|
GT_VEBOX_VDBOX_DISABLE, /* _MMIO(0x9140) */
|
|
XEHP_GT_COMPUTE_DSS_ENABLE, /* _MMIO(0x9144) */
|
|
XEHPC_GT_COMPUTE_DSS_ENABLE_EXT,/* _MMIO(0x9148) */
|
|
CTC_MODE, /* _MMIO(0xA26C) */
|
|
HUC_KERNEL_LOAD_INFO, /* _MMIO(0xc1dc) */
|
|
TIMESTAMP_OVERRIDE, /* _MMIO(0x44074) */
|
|
};
|
|
|
|
static const struct xe_reg ver_1270_runtime_regs[] = {
|
|
RPM_CONFIG0, /* _MMIO(0x0d00) */
|
|
XEHP_FUSE4, /* _MMIO(0x9114) */
|
|
MIRROR_FUSE3, /* _MMIO(0x9118) */
|
|
MIRROR_FUSE1, /* _MMIO(0x911c) */
|
|
XELP_EU_ENABLE, /* _MMIO(0x9134) */
|
|
XELP_GT_GEOMETRY_DSS_ENABLE, /* _MMIO(0x913c) */
|
|
GT_VEBOX_VDBOX_DISABLE, /* _MMIO(0x9140) */
|
|
XEHP_GT_COMPUTE_DSS_ENABLE, /* _MMIO(0x9144) */
|
|
XEHPC_GT_COMPUTE_DSS_ENABLE_EXT,/* _MMIO(0x9148) */
|
|
CTC_MODE, /* _MMIO(0xa26c) */
|
|
HUC_KERNEL_LOAD_INFO, /* _MMIO(0xc1dc) */
|
|
TIMESTAMP_OVERRIDE, /* _MMIO(0x44074) */
|
|
};
|
|
|
|
static const struct xe_reg ver_2000_runtime_regs[] = {
|
|
RPM_CONFIG0, /* _MMIO(0x0d00) */
|
|
XEHP_FUSE4, /* _MMIO(0x9114) */
|
|
MIRROR_FUSE3, /* _MMIO(0x9118) */
|
|
MIRROR_FUSE1, /* _MMIO(0x911c) */
|
|
XELP_EU_ENABLE, /* _MMIO(0x9134) */
|
|
XELP_GT_GEOMETRY_DSS_ENABLE, /* _MMIO(0x913c) */
|
|
GT_VEBOX_VDBOX_DISABLE, /* _MMIO(0x9140) */
|
|
XEHP_GT_COMPUTE_DSS_ENABLE, /* _MMIO(0x9144) */
|
|
XEHPC_GT_COMPUTE_DSS_ENABLE_EXT,/* _MMIO(0x9148) */
|
|
XE2_GT_COMPUTE_DSS_2, /* _MMIO(0x914c) */
|
|
XE2_GT_GEOMETRY_DSS_1, /* _MMIO(0x9150) */
|
|
XE2_GT_GEOMETRY_DSS_2, /* _MMIO(0x9154) */
|
|
CTC_MODE, /* _MMIO(0xa26c) */
|
|
HUC_KERNEL_LOAD_INFO, /* _MMIO(0xc1dc) */
|
|
TIMESTAMP_OVERRIDE, /* _MMIO(0x44074) */
|
|
};
|
|
|
|
static const struct xe_reg *pick_runtime_regs(struct xe_device *xe, unsigned int *count)
|
|
{
|
|
const struct xe_reg *regs;
|
|
|
|
if (GRAPHICS_VERx100(xe) >= 2000) {
|
|
*count = ARRAY_SIZE(ver_2000_runtime_regs);
|
|
regs = ver_2000_runtime_regs;
|
|
} else if (GRAPHICS_VERx100(xe) >= 1270) {
|
|
*count = ARRAY_SIZE(ver_1270_runtime_regs);
|
|
regs = ver_1270_runtime_regs;
|
|
} else if (GRAPHICS_VERx100(xe) == 1260) {
|
|
*count = ARRAY_SIZE(pvc_runtime_regs);
|
|
regs = pvc_runtime_regs;
|
|
} else if (GRAPHICS_VERx100(xe) == 1255) {
|
|
*count = ARRAY_SIZE(ats_m_runtime_regs);
|
|
regs = ats_m_runtime_regs;
|
|
} else if (GRAPHICS_VERx100(xe) == 1200) {
|
|
*count = ARRAY_SIZE(tgl_runtime_regs);
|
|
regs = tgl_runtime_regs;
|
|
} else {
|
|
regs = ERR_PTR(-ENOPKG);
|
|
*count = 0;
|
|
}
|
|
|
|
return regs;
|
|
}
|
|
|
|
static int pf_alloc_runtime_info(struct xe_gt *gt)
|
|
{
|
|
struct xe_device *xe = gt_to_xe(gt);
|
|
const struct xe_reg *regs;
|
|
unsigned int size;
|
|
u32 *values;
|
|
|
|
xe_gt_assert(gt, IS_SRIOV_PF(xe));
|
|
xe_gt_assert(gt, !gt->sriov.pf.service.runtime.size);
|
|
xe_gt_assert(gt, !gt->sriov.pf.service.runtime.regs);
|
|
xe_gt_assert(gt, !gt->sriov.pf.service.runtime.values);
|
|
|
|
regs = pick_runtime_regs(xe, &size);
|
|
if (IS_ERR(regs))
|
|
return PTR_ERR(regs);
|
|
|
|
if (unlikely(!size))
|
|
return 0;
|
|
|
|
values = drmm_kcalloc(&xe->drm, size, sizeof(u32), GFP_KERNEL);
|
|
if (!values)
|
|
return -ENOMEM;
|
|
|
|
gt->sriov.pf.service.runtime.size = size;
|
|
gt->sriov.pf.service.runtime.regs = regs;
|
|
gt->sriov.pf.service.runtime.values = values;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static void read_many(struct xe_gt *gt, unsigned int count,
|
|
const struct xe_reg *regs, u32 *values)
|
|
{
|
|
while (count--)
|
|
*values++ = xe_mmio_read32(gt, *regs++);
|
|
}
|
|
|
|
static void pf_prepare_runtime_info(struct xe_gt *gt)
|
|
{
|
|
const struct xe_reg *regs;
|
|
unsigned int size;
|
|
u32 *values;
|
|
|
|
if (!gt->sriov.pf.service.runtime.size)
|
|
return;
|
|
|
|
size = gt->sriov.pf.service.runtime.size;
|
|
regs = gt->sriov.pf.service.runtime.regs;
|
|
values = gt->sriov.pf.service.runtime.values;
|
|
|
|
read_many(gt, size, regs, values);
|
|
|
|
if (IS_ENABLED(CONFIG_DRM_XE_DEBUG_SRIOV)) {
|
|
struct drm_printer p = xe_gt_info_printer(gt);
|
|
|
|
xe_gt_sriov_pf_service_print_runtime(gt, &p);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* xe_gt_sriov_pf_service_init - Early initialization of the GT SR-IOV PF services.
|
|
* @gt: the &xe_gt to initialize
|
|
*
|
|
* Performs early initialization of the GT SR-IOV PF services, including preparation
|
|
* of the runtime info that will be shared with VFs.
|
|
*
|
|
* This function can only be called on PF.
|
|
*/
|
|
int xe_gt_sriov_pf_service_init(struct xe_gt *gt)
|
|
{
|
|
int err;
|
|
|
|
pf_init_versions(gt);
|
|
|
|
err = pf_alloc_runtime_info(gt);
|
|
if (unlikely(err))
|
|
goto failed;
|
|
|
|
return 0;
|
|
failed:
|
|
xe_gt_sriov_err(gt, "Failed to initialize service (%pe)\n", ERR_PTR(err));
|
|
return err;
|
|
}
|
|
|
|
/**
|
|
* xe_gt_sriov_pf_service_update - Update PF SR-IOV services.
|
|
* @gt: the &xe_gt to update
|
|
*
|
|
* Updates runtime data shared with VFs.
|
|
*
|
|
* This function can be called more than once.
|
|
* This function can only be called on PF.
|
|
*/
|
|
void xe_gt_sriov_pf_service_update(struct xe_gt *gt)
|
|
{
|
|
pf_prepare_runtime_info(gt);
|
|
}
|
|
|
|
/**
|
|
* xe_gt_sriov_pf_service_reset - Reset a connection with the VF.
|
|
* @gt: the &xe_gt
|
|
* @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_gt_sriov_pf_service_reset(struct xe_gt *gt, unsigned int vfid)
|
|
{
|
|
pf_disconnect(gt, vfid);
|
|
}
|
|
|
|
/* Return: 0 on success or a negative error code on failure. */
|
|
static int pf_process_handshake(struct xe_gt *gt, u32 vfid,
|
|
u32 wanted_major, u32 wanted_minor,
|
|
u32 *major, u32 *minor)
|
|
{
|
|
int err;
|
|
|
|
xe_gt_sriov_dbg_verbose(gt, "VF%u wants ABI version %u.%u\n",
|
|
vfid, wanted_major, wanted_minor);
|
|
|
|
err = pf_negotiate_version(gt, wanted_major, wanted_minor, major, minor);
|
|
|
|
if (err < 0) {
|
|
xe_gt_sriov_notice(gt, "VF%u failed to negotiate ABI %u.%u (%pe)\n",
|
|
vfid, wanted_major, wanted_minor, ERR_PTR(err));
|
|
pf_disconnect(gt, vfid);
|
|
} else {
|
|
xe_gt_sriov_dbg(gt, "VF%u negotiated ABI version %u.%u\n",
|
|
vfid, *major, *minor);
|
|
pf_connect(gt, vfid, *major, *minor);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* Return: length of the response message or a negative error code on failure. */
|
|
static int pf_process_handshake_msg(struct xe_gt *gt, u32 origin,
|
|
const u32 *request, u32 len, u32 *response, u32 size)
|
|
{
|
|
u32 wanted_major, wanted_minor;
|
|
u32 major, minor;
|
|
u32 mbz;
|
|
int err;
|
|
|
|
if (unlikely(len != VF2PF_HANDSHAKE_REQUEST_MSG_LEN))
|
|
return -EMSGSIZE;
|
|
|
|
mbz = FIELD_GET(VF2PF_HANDSHAKE_REQUEST_MSG_0_MBZ, request[0]);
|
|
if (unlikely(mbz))
|
|
return -EPFNOSUPPORT;
|
|
|
|
wanted_major = FIELD_GET(VF2PF_HANDSHAKE_REQUEST_MSG_1_MAJOR, request[1]);
|
|
wanted_minor = FIELD_GET(VF2PF_HANDSHAKE_REQUEST_MSG_1_MINOR, request[1]);
|
|
|
|
err = pf_process_handshake(gt, origin, wanted_major, wanted_minor, &major, &minor);
|
|
if (err < 0)
|
|
return err;
|
|
|
|
xe_gt_assert(gt, major || minor);
|
|
xe_gt_assert(gt, size >= VF2PF_HANDSHAKE_RESPONSE_MSG_LEN);
|
|
|
|
response[0] = FIELD_PREP(GUC_HXG_MSG_0_ORIGIN, GUC_HXG_ORIGIN_HOST) |
|
|
FIELD_PREP(GUC_HXG_MSG_0_TYPE, GUC_HXG_TYPE_RESPONSE_SUCCESS) |
|
|
FIELD_PREP(GUC_HXG_RESPONSE_MSG_0_DATA0, 0);
|
|
response[1] = FIELD_PREP(VF2PF_HANDSHAKE_RESPONSE_MSG_1_MAJOR, major) |
|
|
FIELD_PREP(VF2PF_HANDSHAKE_RESPONSE_MSG_1_MINOR, minor);
|
|
|
|
return VF2PF_HANDSHAKE_RESPONSE_MSG_LEN;
|
|
}
|
|
|
|
struct reg_data {
|
|
u32 offset;
|
|
u32 value;
|
|
} __packed;
|
|
static_assert(hxg_sizeof(struct reg_data) == 2);
|
|
|
|
/* Return: number of entries copied or negative error code on failure. */
|
|
static int pf_service_runtime_query(struct xe_gt *gt, u32 start, u32 limit,
|
|
struct reg_data *data, u32 *remaining)
|
|
{
|
|
struct xe_gt_sriov_pf_service_runtime_regs *runtime;
|
|
unsigned int count, i;
|
|
u32 addr;
|
|
|
|
xe_gt_assert(gt, IS_SRIOV_PF(gt_to_xe(gt)));
|
|
|
|
runtime = >->sriov.pf.service.runtime;
|
|
|
|
if (start > runtime->size)
|
|
return -ERANGE;
|
|
|
|
count = min_t(u32, runtime->size - start, limit);
|
|
|
|
for (i = 0; i < count; ++i, ++data) {
|
|
addr = runtime->regs[start + i].addr;
|
|
data->offset = xe_mmio_adjusted_addr(gt, addr);
|
|
data->value = runtime->values[start + i];
|
|
}
|
|
|
|
*remaining = runtime->size - start - count;
|
|
return count;
|
|
}
|
|
|
|
/* Return: length of the response message or a negative error code on failure. */
|
|
static int pf_process_runtime_query_msg(struct xe_gt *gt, u32 origin,
|
|
const u32 *msg, u32 msg_len, u32 *response, u32 resp_size)
|
|
{
|
|
const u32 chunk_size = hxg_sizeof(struct reg_data);
|
|
struct reg_data *reg_data_buf;
|
|
u32 limit, start, max_chunks;
|
|
u32 remaining = 0;
|
|
int ret;
|
|
|
|
if (!pf_is_negotiated(gt, origin, 1, 0))
|
|
return -EACCES;
|
|
if (unlikely(msg_len > VF2PF_QUERY_RUNTIME_REQUEST_MSG_LEN))
|
|
return -EMSGSIZE;
|
|
if (unlikely(msg_len < VF2PF_QUERY_RUNTIME_REQUEST_MSG_LEN))
|
|
return -EPROTO;
|
|
if (unlikely(resp_size < VF2PF_QUERY_RUNTIME_RESPONSE_MSG_MIN_LEN))
|
|
return -EINVAL;
|
|
|
|
limit = FIELD_GET(VF2PF_QUERY_RUNTIME_REQUEST_MSG_0_LIMIT, msg[0]);
|
|
start = FIELD_GET(VF2PF_QUERY_RUNTIME_REQUEST_MSG_1_START, msg[1]);
|
|
|
|
resp_size = min_t(u32, resp_size, VF2PF_QUERY_RUNTIME_RESPONSE_MSG_MAX_LEN);
|
|
max_chunks = (resp_size - VF2PF_QUERY_RUNTIME_RESPONSE_MSG_MIN_LEN) / chunk_size;
|
|
limit = limit == VF2PF_QUERY_RUNTIME_NO_LIMIT ? max_chunks : min_t(u32, max_chunks, limit);
|
|
reg_data_buf = (void *)(response + VF2PF_QUERY_RUNTIME_RESPONSE_MSG_MIN_LEN);
|
|
|
|
ret = pf_service_runtime_query(gt, start, limit, reg_data_buf, &remaining);
|
|
if (ret < 0)
|
|
return ret;
|
|
|
|
response[0] = FIELD_PREP(GUC_HXG_MSG_0_ORIGIN, GUC_HXG_ORIGIN_HOST) |
|
|
FIELD_PREP(GUC_HXG_MSG_0_TYPE, GUC_HXG_TYPE_RESPONSE_SUCCESS) |
|
|
FIELD_PREP(VF2PF_QUERY_RUNTIME_RESPONSE_MSG_0_COUNT, ret);
|
|
response[1] = FIELD_PREP(VF2PF_QUERY_RUNTIME_RESPONSE_MSG_1_REMAINING, remaining);
|
|
|
|
return VF2PF_QUERY_RUNTIME_RESPONSE_MSG_MIN_LEN + ret * hxg_sizeof(struct reg_data);
|
|
}
|
|
|
|
/**
|
|
* xe_gt_sriov_pf_service_process_request - Service GT level SR-IOV request message from the VF.
|
|
* @gt: the &xe_gt that provides the service
|
|
* @origin: VF number that is requesting the service
|
|
* @msg: request message
|
|
* @msg_len: length of the request message (in dwords)
|
|
* @response: placeholder for the response message
|
|
* @resp_size: length of the response message buffer (in dwords)
|
|
*
|
|
* This function processes `Relay Message`_ request from the VF.
|
|
*
|
|
* Return: length of the response message or a negative error code on failure.
|
|
*/
|
|
int xe_gt_sriov_pf_service_process_request(struct xe_gt *gt, u32 origin,
|
|
const u32 *msg, u32 msg_len,
|
|
u32 *response, u32 resp_size)
|
|
{
|
|
u32 action, data __maybe_unused;
|
|
int ret;
|
|
|
|
xe_gt_assert(gt, msg_len >= GUC_HXG_MSG_MIN_LEN);
|
|
xe_gt_assert(gt, FIELD_GET(GUC_HXG_MSG_0_TYPE, msg[0]) == GUC_HXG_TYPE_REQUEST);
|
|
|
|
action = FIELD_GET(GUC_HXG_REQUEST_MSG_0_ACTION, msg[0]);
|
|
data = FIELD_GET(GUC_HXG_REQUEST_MSG_0_DATA0, msg[0]);
|
|
xe_gt_sriov_dbg_verbose(gt, "service action %#x:%u from VF%u\n",
|
|
action, data, origin);
|
|
|
|
switch (action) {
|
|
case GUC_RELAY_ACTION_VF2PF_HANDSHAKE:
|
|
ret = pf_process_handshake_msg(gt, origin, msg, msg_len, response, resp_size);
|
|
break;
|
|
case GUC_RELAY_ACTION_VF2PF_QUERY_RUNTIME:
|
|
ret = pf_process_runtime_query_msg(gt, origin, msg, msg_len, response, resp_size);
|
|
break;
|
|
default:
|
|
ret = -EOPNOTSUPP;
|
|
break;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
/**
|
|
* xe_gt_sriov_pf_service_print_runtime - Print PF runtime data shared with VFs.
|
|
* @gt: the &xe_gt
|
|
* @p: the &drm_printer
|
|
*
|
|
* This function is for PF use only.
|
|
*/
|
|
int xe_gt_sriov_pf_service_print_runtime(struct xe_gt *gt, struct drm_printer *p)
|
|
{
|
|
const struct xe_reg *regs;
|
|
unsigned int size;
|
|
u32 *values;
|
|
|
|
xe_gt_assert(gt, IS_SRIOV_PF(gt_to_xe(gt)));
|
|
|
|
size = gt->sriov.pf.service.runtime.size;
|
|
regs = gt->sriov.pf.service.runtime.regs;
|
|
values = gt->sriov.pf.service.runtime.values;
|
|
|
|
for (; size--; regs++, values++) {
|
|
drm_printf(p, "reg[%#x] = %#x\n",
|
|
xe_mmio_adjusted_addr(gt, regs->addr), *values);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* xe_gt_sriov_pf_service_print_version - Print ABI versions negotiated with VFs.
|
|
* @gt: the &xe_gt
|
|
* @p: the &drm_printer
|
|
*
|
|
* This function is for PF use only.
|
|
*/
|
|
int xe_gt_sriov_pf_service_print_version(struct xe_gt *gt, struct drm_printer *p)
|
|
{
|
|
struct xe_device *xe = gt_to_xe(gt);
|
|
unsigned int n, total_vfs = xe_sriov_pf_get_totalvfs(xe);
|
|
struct xe_gt_sriov_pf_service_version *version;
|
|
|
|
xe_gt_assert(gt, IS_SRIOV_PF(xe));
|
|
|
|
for (n = 1; n <= total_vfs; n++) {
|
|
version = >->sriov.pf.vfs[n].version;
|
|
if (!version->major && !version->minor)
|
|
continue;
|
|
|
|
drm_printf(p, "VF%u:\t%u.%u\n", n, version->major, version->minor);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
#if IS_BUILTIN(CONFIG_DRM_XE_KUNIT_TEST)
|
|
#include "tests/xe_gt_sriov_pf_service_test.c"
|
|
#endif
|