[PATCH 4/5] drm/xe/pf: Add SR-IOV GuC Relay PF services
Piotr Piórkowski
piotr.piorkowski at intel.com
Mon Apr 22 10:48:19 UTC 2024
Michal Wajdeczko <michal.wajdeczko at intel.com> wrote on czw [2024-kwi-18 17:28:01 +0200]:
> We already have mechanism that allows a VF driver to communicate
> with the PF driver, now add PF side handlers for VF2PF requests
> defined in version 1.0 of VF/PF GuC Relay ABI specification.
>
> The VF2PF_HANDSHAKE request must be used by the VF driver to
> negotiate the ABI version prior to sending any other request.
> We will reset any negotiated version later during FLR.
>
> The outcome of the VF2PF_QUERY_RUNTIME requests depends on actual
> platform, for legacy platforms used as SDV is provided as-is, for
> latest platforms it is preliminary, and might be changed.
>
> Signed-off-by: Michal Wajdeczko <michal.wajdeczko at intel.com>
> ---
> drivers/gpu/drm/xe/Makefile | 1 +
> drivers/gpu/drm/xe/xe_gt_sriov_pf_service.c | 549 ++++++++++++++++++
> drivers/gpu/drm/xe/xe_gt_sriov_pf_service.h | 36 ++
> .../gpu/drm/xe/xe_gt_sriov_pf_service_types.h | 52 ++
> drivers/gpu/drm/xe/xe_gt_sriov_pf_types.h | 5 +
> drivers/gpu/drm/xe/xe_guc_relay.c | 8 +-
> 6 files changed, 649 insertions(+), 2 deletions(-)
> create mode 100644 drivers/gpu/drm/xe/xe_gt_sriov_pf_service.c
> create mode 100644 drivers/gpu/drm/xe/xe_gt_sriov_pf_service.h
> create mode 100644 drivers/gpu/drm/xe/xe_gt_sriov_pf_service_types.h
>
> diff --git a/drivers/gpu/drm/xe/Makefile b/drivers/gpu/drm/xe/Makefile
> index 8321ec4f9b46..5ca09cb03363 100644
> --- a/drivers/gpu/drm/xe/Makefile
> +++ b/drivers/gpu/drm/xe/Makefile
> @@ -164,6 +164,7 @@ xe-$(CONFIG_PCI_IOV) += \
> xe_gt_sriov_pf_config.o \
> xe_gt_sriov_pf_control.o \
> xe_gt_sriov_pf_policy.o \
> + xe_gt_sriov_pf_service.o \
> xe_lmtt.o \
> xe_lmtt_2l.o \
> xe_lmtt_ml.o \
> diff --git a/drivers/gpu/drm/xe/xe_gt_sriov_pf_service.c b/drivers/gpu/drm/xe/xe_gt_sriov_pf_service.c
> new file mode 100644
> index 000000000000..4b9850cc3615
> --- /dev/null
> +++ b/drivers/gpu/drm/xe/xe_gt_sriov_pf_service.c
> @@ -0,0 +1,549 @@
> +// 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)
Did you have any reason to format these function parameters so strangely ?
> +{
> + 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 ? min_t(u32, max_chunks, limit) : max_chunks;
> + 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;
> +}
> diff --git a/drivers/gpu/drm/xe/xe_gt_sriov_pf_service.h b/drivers/gpu/drm/xe/xe_gt_sriov_pf_service.h
> new file mode 100644
> index 000000000000..56aaadf0360d
> --- /dev/null
> +++ b/drivers/gpu/drm/xe/xe_gt_sriov_pf_service.h
> @@ -0,0 +1,36 @@
> +/* SPDX-License-Identifier: MIT */
> +/*
> + * Copyright © 2023-2024 Intel Corporation
> + */
> +
> +#ifndef _XE_GT_SRIOV_PF_SERVICE_H_
> +#define _XE_GT_SRIOV_PF_SERVICE_H_
> +
> +#include <linux/errno.h>
> +#include <linux/types.h>
> +
> +struct drm_printer;
> +struct xe_gt;
> +
> +int xe_gt_sriov_pf_service_init(struct xe_gt *gt);
> +void xe_gt_sriov_pf_service_update(struct xe_gt *gt);
> +void xe_gt_sriov_pf_service_reset(struct xe_gt *gt, unsigned int vfid);
> +
> +int xe_gt_sriov_pf_service_print_version(struct xe_gt *gt, struct drm_printer *p);
> +int xe_gt_sriov_pf_service_print_runtime(struct xe_gt *gt, struct drm_printer *p);
> +
> +#ifdef CONFIG_PCI_IOV
> +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);
> +#else
> +static inline 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)
> +{
> + return -EPROTO;
> +}
> +#endif
> +
> +#endif
> diff --git a/drivers/gpu/drm/xe/xe_gt_sriov_pf_service_types.h b/drivers/gpu/drm/xe/xe_gt_sriov_pf_service_types.h
> new file mode 100644
> index 000000000000..428a3ebf7811
> --- /dev/null
> +++ b/drivers/gpu/drm/xe/xe_gt_sriov_pf_service_types.h
> @@ -0,0 +1,52 @@
> +/* SPDX-License-Identifier: MIT */
> +/*
> + * Copyright © 2023-2024 Intel Corporation
> + */
> +
> +#ifndef _XE_GT_SRIOV_PF_SERVICE_TYPES_H_
> +#define _XE_GT_SRIOV_PF_SERVICE_TYPES_H_
> +
> +#include <linux/types.h>
> +
> +struct xe_reg;
> +
> +/**
> + * struct xe_gt_sriov_pf_service_version - VF/PF ABI Version.
> + * @major: the major version of the VF/PF ABI
> + * @minor: the minor version of the VF/PF ABI
> + *
> + * See `GuC Relay Communication`_.
> + */
> +struct xe_gt_sriov_pf_service_version {
> + u16 major;
> + u16 minor;
> +};
> +
> +/**
> + * struct xe_gt_sriov_pf_service_runtime_regs - Runtime data shared with VFs.
> + * @regs: pointer to static array with register offsets.
> + * @values: pointer to array with captured register values.
> + * @size: size of the regs and value arrays.
> + */
> +struct xe_gt_sriov_pf_service_runtime_regs {
> + const struct xe_reg *regs;
> + u32 *values;
> + u32 size;
> +};
> +
> +/**
> + * struct xe_gt_sriov_service - Placeholder for the PF service data shared with VFs.
> + * @version: information about VF/PF ABI versions for current platform.
> + * @version.base: lowest VF/PF ABI version that could be negotiated with VF.
> + * @version.latest: latest VF/PF ABI version supported by the PF driver.
> + * @runtime: runtime data shared with VFs.
> + */
You should propably rephrase this description differently and remove the placeholder phrase
> +struct xe_gt_sriov_pf_service {
> + struct {
> + struct xe_gt_sriov_pf_service_version base;
> + struct xe_gt_sriov_pf_service_version latest;
> + } version;
> + struct xe_gt_sriov_pf_service_runtime_regs runtime;
> +};
> +
> +#endif
> diff --git a/drivers/gpu/drm/xe/xe_gt_sriov_pf_types.h b/drivers/gpu/drm/xe/xe_gt_sriov_pf_types.h
> index faf9ee8266ce..880754f3e215 100644
> --- a/drivers/gpu/drm/xe/xe_gt_sriov_pf_types.h
> +++ b/drivers/gpu/drm/xe/xe_gt_sriov_pf_types.h
> @@ -10,6 +10,7 @@
>
> #include "xe_gt_sriov_pf_config_types.h"
> #include "xe_gt_sriov_pf_policy_types.h"
> +#include "xe_gt_sriov_pf_service_types.h"
>
> /**
> * struct xe_gt_sriov_metadata - GT level per-VF metadata.
> @@ -17,15 +18,19 @@
> struct xe_gt_sriov_metadata {
> /** @config: per-VF provisioning data. */
> struct xe_gt_sriov_config config;
> + /** @version: negotiated VF/PF ABI version */
> + struct xe_gt_sriov_pf_service_version version;
> };
>
> /**
> * struct xe_gt_sriov_pf - GT level PF virtualization data.
> + * @service: service data.
> * @policy: policy data.
> * @spare: PF-only provisioning configuration.
> * @vfs: metadata for all VFs.
> */
> struct xe_gt_sriov_pf {
> + struct xe_gt_sriov_pf_service service;
> struct xe_gt_sriov_pf_policy policy;
> struct xe_gt_sriov_spare_config spare;
> struct xe_gt_sriov_metadata *vfs;
> diff --git a/drivers/gpu/drm/xe/xe_guc_relay.c b/drivers/gpu/drm/xe/xe_guc_relay.c
> index c0a2d8d5d3b3..c3bbaf474f9a 100644
> --- a/drivers/gpu/drm/xe/xe_guc_relay.c
> +++ b/drivers/gpu/drm/xe/xe_guc_relay.c
> @@ -19,6 +19,7 @@
> #include "xe_device.h"
> #include "xe_gt.h"
> #include "xe_gt_sriov_printk.h"
> +#include "xe_gt_sriov_pf_service.h"
> #include "xe_guc.h"
> #include "xe_guc_ct.h"
> #include "xe_guc_hxg_helpers.h"
> @@ -664,6 +665,7 @@ static int relay_testloop_action_handler(struct xe_guc_relay *relay, u32 origin,
> static int relay_action_handler(struct xe_guc_relay *relay, u32 origin,
> const u32 *msg, u32 len, u32 *response, u32 size)
> {
> + struct xe_gt *gt = relay_to_gt(relay);
> u32 type;
> int ret;
>
> @@ -674,8 +676,10 @@ static int relay_action_handler(struct xe_guc_relay *relay, u32 origin,
>
> type = FIELD_GET(GUC_HXG_MSG_0_TYPE, msg[0]);
>
> - /* XXX: PF services will be added later */
> - ret = -EOPNOTSUPP;
> + if (IS_SRIOV_PF(relay_to_xe(relay)))
> + ret = xe_gt_sriov_pf_service_process_request(gt, origin, msg, len, response, size);
> + else
> + ret = -EOPNOTSUPP;
>
> if (type == GUC_HXG_TYPE_EVENT)
> relay_assert(relay, ret <= 0);
The code seems fine to me. Two minor comments.
But still: Reviewed-by: Piotr Piórkowski <piotr.piorkowski at intel.com>
> --
> 2.43.0
>
--
More information about the Intel-xe
mailing list