brintos

brintos / linux-shallow public Read only

0
0
Text · 27.2 KiB · 4ebc82e Raw
1020 lines · c
1// SPDX-License-Identifier: MIT2/*3 * Copyright © 2023-2024 Intel Corporation4 */5 6#include <linux/bitfield.h>7#include <linux/bsearch.h>8 9#include <drm/drm_managed.h>10#include <drm/drm_print.h>11 12#include "abi/guc_actions_sriov_abi.h"13#include "abi/guc_communication_mmio_abi.h"14#include "abi/guc_klvs_abi.h"15#include "abi/guc_relay_actions_abi.h"16#include "regs/xe_gt_regs.h"17#include "regs/xe_gtt_defs.h"18 19#include "xe_assert.h"20#include "xe_device.h"21#include "xe_ggtt.h"22#include "xe_gt_sriov_printk.h"23#include "xe_gt_sriov_vf.h"24#include "xe_gt_sriov_vf_types.h"25#include "xe_guc.h"26#include "xe_guc_hxg_helpers.h"27#include "xe_guc_relay.h"28#include "xe_mmio.h"29#include "xe_sriov.h"30#include "xe_uc_fw.h"31#include "xe_wopcm.h"32 33#define make_u64_from_u32(hi, lo) ((u64)((u64)(u32)(hi) << 32 | (u32)(lo)))34 35static int guc_action_vf_reset(struct xe_guc *guc)36{37	u32 request[GUC_HXG_REQUEST_MSG_MIN_LEN] = {38		FIELD_PREP(GUC_HXG_MSG_0_ORIGIN, GUC_HXG_ORIGIN_HOST) |39		FIELD_PREP(GUC_HXG_MSG_0_TYPE, GUC_HXG_TYPE_REQUEST) |40		FIELD_PREP(GUC_HXG_REQUEST_MSG_0_ACTION, GUC_ACTION_VF2GUC_VF_RESET),41	};42	int ret;43 44	ret = xe_guc_mmio_send(guc, request, ARRAY_SIZE(request));45 46	return ret > 0 ? -EPROTO : ret;47}48 49static int vf_reset_guc_state(struct xe_gt *gt)50{51	struct xe_guc *guc = &gt->uc.guc;52	int err;53 54	err = guc_action_vf_reset(guc);55	if (unlikely(err))56		xe_gt_sriov_err(gt, "Failed to reset GuC state (%pe)\n", ERR_PTR(err));57	return err;58}59 60static int guc_action_match_version(struct xe_guc *guc,61				    u32 wanted_branch, u32 wanted_major, u32 wanted_minor,62				    u32 *branch, u32 *major, u32 *minor, u32 *patch)63{64	u32 request[VF2GUC_MATCH_VERSION_REQUEST_MSG_LEN] = {65		FIELD_PREP(GUC_HXG_MSG_0_ORIGIN, GUC_HXG_ORIGIN_HOST) |66		FIELD_PREP(GUC_HXG_MSG_0_TYPE, GUC_HXG_TYPE_REQUEST) |67		FIELD_PREP(GUC_HXG_REQUEST_MSG_0_ACTION,68			   GUC_ACTION_VF2GUC_MATCH_VERSION),69		FIELD_PREP(VF2GUC_MATCH_VERSION_REQUEST_MSG_1_BRANCH, wanted_branch) |70		FIELD_PREP(VF2GUC_MATCH_VERSION_REQUEST_MSG_1_MAJOR, wanted_major) |71		FIELD_PREP(VF2GUC_MATCH_VERSION_REQUEST_MSG_1_MINOR, wanted_minor),72	};73	u32 response[GUC_MAX_MMIO_MSG_LEN];74	int ret;75 76	BUILD_BUG_ON(VF2GUC_MATCH_VERSION_RESPONSE_MSG_LEN > GUC_MAX_MMIO_MSG_LEN);77 78	ret = xe_guc_mmio_send_recv(guc, request, ARRAY_SIZE(request), response);79	if (unlikely(ret < 0))80		return ret;81 82	if (unlikely(FIELD_GET(VF2GUC_MATCH_VERSION_RESPONSE_MSG_0_MBZ, response[0])))83		return -EPROTO;84 85	*branch = FIELD_GET(VF2GUC_MATCH_VERSION_RESPONSE_MSG_1_BRANCH, response[1]);86	*major = FIELD_GET(VF2GUC_MATCH_VERSION_RESPONSE_MSG_1_MAJOR, response[1]);87	*minor = FIELD_GET(VF2GUC_MATCH_VERSION_RESPONSE_MSG_1_MINOR, response[1]);88	*patch = FIELD_GET(VF2GUC_MATCH_VERSION_RESPONSE_MSG_1_PATCH, response[1]);89 90	return 0;91}92 93static void vf_minimum_guc_version(struct xe_gt *gt, u32 *branch, u32 *major, u32 *minor)94{95	struct xe_device *xe = gt_to_xe(gt);96 97	switch (xe->info.platform) {98	case XE_TIGERLAKE ... XE_PVC:99		/* 1.1 this is current baseline for Xe driver */100		*branch = 0;101		*major = 1;102		*minor = 1;103		break;104	default:105		/* 1.2 has support for the GMD_ID KLV */106		*branch = 0;107		*major = 1;108		*minor = 2;109		break;110	}111}112 113static void vf_wanted_guc_version(struct xe_gt *gt, u32 *branch, u32 *major, u32 *minor)114{115	/* for now it's the same as minimum */116	return vf_minimum_guc_version(gt, branch, major, minor);117}118 119static int vf_handshake_with_guc(struct xe_gt *gt)120{121	struct xe_gt_sriov_vf_guc_version *guc_version = &gt->sriov.vf.guc_version;122	struct xe_guc *guc = &gt->uc.guc;123	u32 wanted_branch, wanted_major, wanted_minor;124	u32 branch, major, minor, patch;125	int err;126 127	xe_gt_assert(gt, IS_SRIOV_VF(gt_to_xe(gt)));128 129	/* select wanted version - prefer previous (if any) */130	if (guc_version->major || guc_version->minor) {131		wanted_branch = guc_version->branch;132		wanted_major = guc_version->major;133		wanted_minor = guc_version->minor;134	} else {135		vf_wanted_guc_version(gt, &wanted_branch, &wanted_major, &wanted_minor);136		xe_gt_assert(gt, wanted_major != GUC_VERSION_MAJOR_ANY);137	}138 139	err = guc_action_match_version(guc, wanted_branch, wanted_major, wanted_minor,140				       &branch, &major, &minor, &patch);141	if (unlikely(err))142		goto fail;143 144	/* we don't support interface version change */145	if ((guc_version->major || guc_version->minor) &&146	    (guc_version->branch != branch || guc_version->major != major ||147	     guc_version->minor != minor)) {148		xe_gt_sriov_err(gt, "New GuC interface version detected: %u.%u.%u.%u\n",149				branch, major, minor, patch);150		xe_gt_sriov_info(gt, "Previously used version was: %u.%u.%u.%u\n",151				 guc_version->branch, guc_version->major,152				 guc_version->minor, guc_version->patch);153		err = -EREMCHG;154		goto fail;155	}156 157	/* illegal */158	if (major > wanted_major) {159		err = -EPROTO;160		goto unsupported;161	}162 163	/* there's no fallback on major version. */164	if (major != wanted_major) {165		err = -ENOPKG;166		goto unsupported;167	}168 169	/* check against minimum version supported by us */170	vf_minimum_guc_version(gt, &wanted_branch, &wanted_major, &wanted_minor);171	xe_gt_assert(gt, major != GUC_VERSION_MAJOR_ANY);172	if (major < wanted_major || (major == wanted_major && minor < wanted_minor)) {173		err = -ENOKEY;174		goto unsupported;175	}176 177	xe_gt_sriov_dbg(gt, "using GuC interface version %u.%u.%u.%u\n",178			branch, major, minor, patch);179 180	guc_version->branch = branch;181	guc_version->major = major;182	guc_version->minor = minor;183	guc_version->patch = patch;184	return 0;185 186unsupported:187	xe_gt_sriov_err(gt, "Unsupported GuC version %u.%u.%u.%u (%pe)\n",188			branch, major, minor, patch, ERR_PTR(err));189fail:190	xe_gt_sriov_err(gt, "Unable to confirm GuC version %u.%u (%pe)\n",191			wanted_major, wanted_minor, ERR_PTR(err));192 193	/* try again with *any* just to query which version is supported */194	if (!guc_action_match_version(guc, GUC_VERSION_BRANCH_ANY,195				      GUC_VERSION_MAJOR_ANY, GUC_VERSION_MINOR_ANY,196				      &branch, &major, &minor, &patch))197		xe_gt_sriov_notice(gt, "GuC reports interface version %u.%u.%u.%u\n",198				   branch, major, minor, patch);199	return err;200}201 202/**203 * xe_gt_sriov_vf_bootstrap - Query and setup GuC ABI interface version.204 * @gt: the &xe_gt205 *206 * This function is for VF use only.207 * It requires functional `GuC MMIO based communication`_.208 *209 * Return: 0 on success or a negative error code on failure.210 */211int xe_gt_sriov_vf_bootstrap(struct xe_gt *gt)212{213	int err;214 215	err = vf_reset_guc_state(gt);216	if (unlikely(err))217		return err;218 219	err = vf_handshake_with_guc(gt);220	if (unlikely(err))221		return err;222 223	return 0;224}225 226static int guc_action_query_single_klv(struct xe_guc *guc, u32 key,227				       u32 *value, u32 value_len)228{229	u32 request[VF2GUC_QUERY_SINGLE_KLV_REQUEST_MSG_LEN] = {230		FIELD_PREP(GUC_HXG_MSG_0_ORIGIN, GUC_HXG_ORIGIN_HOST) |231		FIELD_PREP(GUC_HXG_MSG_0_TYPE, GUC_HXG_TYPE_REQUEST) |232		FIELD_PREP(GUC_HXG_REQUEST_MSG_0_ACTION,233			   GUC_ACTION_VF2GUC_QUERY_SINGLE_KLV),234		FIELD_PREP(VF2GUC_QUERY_SINGLE_KLV_REQUEST_MSG_1_KEY, key),235	};236	u32 response[GUC_MAX_MMIO_MSG_LEN];237	u32 length;238	int ret;239 240	BUILD_BUG_ON(VF2GUC_QUERY_SINGLE_KLV_RESPONSE_MSG_MAX_LEN > GUC_MAX_MMIO_MSG_LEN);241	ret = xe_guc_mmio_send_recv(guc, request, ARRAY_SIZE(request), response);242	if (unlikely(ret < 0))243		return ret;244 245	if (unlikely(FIELD_GET(VF2GUC_QUERY_SINGLE_KLV_RESPONSE_MSG_0_MBZ, response[0])))246		return -EPROTO;247 248	length = FIELD_GET(VF2GUC_QUERY_SINGLE_KLV_RESPONSE_MSG_0_LENGTH, response[0]);249	if (unlikely(length > value_len))250		return -EOVERFLOW;251	if (unlikely(length < value_len))252		return -ENODATA;253 254	switch (value_len) {255	default:256		xe_gt_WARN_ON(guc_to_gt(guc), value_len > 3);257		fallthrough;258	case 3:259		value[2] = FIELD_GET(VF2GUC_QUERY_SINGLE_KLV_RESPONSE_MSG_3_VALUE96, response[3]);260		fallthrough;261	case 2:262		value[1] = FIELD_GET(VF2GUC_QUERY_SINGLE_KLV_RESPONSE_MSG_2_VALUE64, response[2]);263		fallthrough;264	case 1:265		value[0] = FIELD_GET(VF2GUC_QUERY_SINGLE_KLV_RESPONSE_MSG_1_VALUE32, response[1]);266		fallthrough;267	case 0:268		break;269	}270 271	return 0;272}273 274static int guc_action_query_single_klv32(struct xe_guc *guc, u32 key, u32 *value32)275{276	return guc_action_query_single_klv(guc, key, value32, hxg_sizeof(u32));277}278 279static int guc_action_query_single_klv64(struct xe_guc *guc, u32 key, u64 *value64)280{281	u32 value[2];282	int err;283 284	err = guc_action_query_single_klv(guc, key, value, hxg_sizeof(value));285	if (unlikely(err))286		return err;287 288	*value64 = make_u64_from_u32(value[1], value[0]);289	return 0;290}291 292static bool has_gmdid(struct xe_device *xe)293{294	return GRAPHICS_VERx100(xe) >= 1270;295}296 297/**298 * xe_gt_sriov_vf_gmdid - Query GMDID over MMIO.299 * @gt: the &xe_gt300 *301 * This function is for VF use only.302 *303 * Return: value of GMDID KLV on success or 0 on failure.304 */305u32 xe_gt_sriov_vf_gmdid(struct xe_gt *gt)306{307	const char *type = xe_gt_is_media_type(gt) ? "media" : "graphics";308	struct xe_guc *guc = &gt->uc.guc;309	u32 value;310	int err;311 312	xe_gt_assert(gt, IS_SRIOV_VF(gt_to_xe(gt)));313	xe_gt_assert(gt, !GRAPHICS_VERx100(gt_to_xe(gt)) || has_gmdid(gt_to_xe(gt)));314	xe_gt_assert(gt, gt->sriov.vf.guc_version.major > 1 || gt->sriov.vf.guc_version.minor >= 2);315 316	err = guc_action_query_single_klv32(guc, GUC_KLV_GLOBAL_CFG_GMD_ID_KEY, &value);317	if (unlikely(err)) {318		xe_gt_sriov_err(gt, "Failed to obtain %s GMDID (%pe)\n",319				type, ERR_PTR(err));320		return 0;321	}322 323	xe_gt_sriov_dbg(gt, "%s GMDID = %#x\n", type, value);324	return value;325}326 327static int vf_get_ggtt_info(struct xe_gt *gt)328{329	struct xe_gt_sriov_vf_selfconfig *config = &gt->sriov.vf.self_config;330	struct xe_guc *guc = &gt->uc.guc;331	u64 start, size;332	int err;333 334	xe_gt_assert(gt, IS_SRIOV_VF(gt_to_xe(gt)));335 336	err = guc_action_query_single_klv64(guc, GUC_KLV_VF_CFG_GGTT_START_KEY, &start);337	if (unlikely(err))338		return err;339 340	err = guc_action_query_single_klv64(guc, GUC_KLV_VF_CFG_GGTT_SIZE_KEY, &size);341	if (unlikely(err))342		return err;343 344	if (config->ggtt_size && config->ggtt_size != size) {345		xe_gt_sriov_err(gt, "Unexpected GGTT reassignment: %lluK != %lluK\n",346				size / SZ_1K, config->ggtt_size / SZ_1K);347		return -EREMCHG;348	}349 350	xe_gt_sriov_dbg_verbose(gt, "GGTT %#llx-%#llx = %lluK\n",351				start, start + size - 1, size / SZ_1K);352 353	config->ggtt_base = start;354	config->ggtt_size = size;355 356	return config->ggtt_size ? 0 : -ENODATA;357}358 359static int vf_get_lmem_info(struct xe_gt *gt)360{361	struct xe_gt_sriov_vf_selfconfig *config = &gt->sriov.vf.self_config;362	struct xe_guc *guc = &gt->uc.guc;363	char size_str[10];364	u64 size;365	int err;366 367	xe_gt_assert(gt, IS_SRIOV_VF(gt_to_xe(gt)));368 369	err = guc_action_query_single_klv64(guc, GUC_KLV_VF_CFG_LMEM_SIZE_KEY, &size);370	if (unlikely(err))371		return err;372 373	if (config->lmem_size && config->lmem_size != size) {374		xe_gt_sriov_err(gt, "Unexpected LMEM reassignment: %lluM != %lluM\n",375				size / SZ_1M, config->lmem_size / SZ_1M);376		return -EREMCHG;377	}378 379	string_get_size(size, 1, STRING_UNITS_2, size_str, sizeof(size_str));380	xe_gt_sriov_dbg_verbose(gt, "LMEM %lluM %s\n", size / SZ_1M, size_str);381 382	config->lmem_size = size;383 384	return config->lmem_size ? 0 : -ENODATA;385}386 387static int vf_get_submission_cfg(struct xe_gt *gt)388{389	struct xe_gt_sriov_vf_selfconfig *config = &gt->sriov.vf.self_config;390	struct xe_guc *guc = &gt->uc.guc;391	u32 num_ctxs, num_dbs;392	int err;393 394	xe_gt_assert(gt, IS_SRIOV_VF(gt_to_xe(gt)));395 396	err = guc_action_query_single_klv32(guc, GUC_KLV_VF_CFG_NUM_CONTEXTS_KEY, &num_ctxs);397	if (unlikely(err))398		return err;399 400	err = guc_action_query_single_klv32(guc, GUC_KLV_VF_CFG_NUM_DOORBELLS_KEY, &num_dbs);401	if (unlikely(err))402		return err;403 404	if (config->num_ctxs && config->num_ctxs != num_ctxs) {405		xe_gt_sriov_err(gt, "Unexpected CTXs reassignment: %u != %u\n",406				num_ctxs, config->num_ctxs);407		return -EREMCHG;408	}409	if (config->num_dbs && config->num_dbs != num_dbs) {410		xe_gt_sriov_err(gt, "Unexpected DBs reassignment: %u != %u\n",411				num_dbs, config->num_dbs);412		return -EREMCHG;413	}414 415	xe_gt_sriov_dbg_verbose(gt, "CTXs %u DBs %u\n", num_ctxs, num_dbs);416 417	config->num_ctxs = num_ctxs;418	config->num_dbs = num_dbs;419 420	return config->num_ctxs ? 0 : -ENODATA;421}422 423static void vf_cache_gmdid(struct xe_gt *gt)424{425	xe_gt_assert(gt, has_gmdid(gt_to_xe(gt)));426	xe_gt_assert(gt, IS_SRIOV_VF(gt_to_xe(gt)));427 428	gt->sriov.vf.runtime.gmdid = xe_gt_sriov_vf_gmdid(gt);429}430 431/**432 * xe_gt_sriov_vf_query_config - Query SR-IOV config data over MMIO.433 * @gt: the &xe_gt434 *435 * This function is for VF use only.436 *437 * Return: 0 on success or a negative error code on failure.438 */439int xe_gt_sriov_vf_query_config(struct xe_gt *gt)440{441	struct xe_device *xe = gt_to_xe(gt);442	int err;443 444	err = vf_get_ggtt_info(gt);445	if (unlikely(err))446		return err;447 448	if (IS_DGFX(xe) && !xe_gt_is_media_type(gt)) {449		err = vf_get_lmem_info(gt);450		if (unlikely(err))451			return err;452	}453 454	err = vf_get_submission_cfg(gt);455	if (unlikely(err))456		return err;457 458	if (has_gmdid(xe))459		vf_cache_gmdid(gt);460 461	return 0;462}463 464/**465 * xe_gt_sriov_vf_guc_ids - VF GuC context IDs configuration.466 * @gt: the &xe_gt467 *468 * This function is for VF use only.469 *470 * Return: number of GuC context IDs assigned to VF.471 */472u16 xe_gt_sriov_vf_guc_ids(struct xe_gt *gt)473{474	xe_gt_assert(gt, IS_SRIOV_VF(gt_to_xe(gt)));475	xe_gt_assert(gt, gt->sriov.vf.guc_version.major);476	xe_gt_assert(gt, gt->sriov.vf.self_config.num_ctxs);477 478	return gt->sriov.vf.self_config.num_ctxs;479}480 481/**482 * xe_gt_sriov_vf_lmem - VF LMEM configuration.483 * @gt: the &xe_gt484 *485 * This function is for VF use only.486 *487 * Return: size of the LMEM assigned to VF.488 */489u64 xe_gt_sriov_vf_lmem(struct xe_gt *gt)490{491	xe_gt_assert(gt, IS_SRIOV_VF(gt_to_xe(gt)));492	xe_gt_assert(gt, gt->sriov.vf.guc_version.major);493	xe_gt_assert(gt, gt->sriov.vf.self_config.lmem_size);494 495	return gt->sriov.vf.self_config.lmem_size;496}497 498static struct xe_ggtt_node *499vf_balloon_ggtt_node(struct xe_ggtt *ggtt, u64 start, u64 end)500{501	struct xe_ggtt_node *node;502	int err;503 504	node = xe_ggtt_node_init(ggtt);505	if (IS_ERR(node))506		return node;507 508	err = xe_ggtt_node_insert_balloon(node, start, end);509	if (err) {510		xe_ggtt_node_fini(node);511		return ERR_PTR(err);512	}513 514	return node;515}516 517static int vf_balloon_ggtt(struct xe_gt *gt)518{519	struct xe_gt_sriov_vf_selfconfig *config = &gt->sriov.vf.self_config;520	struct xe_tile *tile = gt_to_tile(gt);521	struct xe_ggtt *ggtt = tile->mem.ggtt;522	struct xe_device *xe = gt_to_xe(gt);523	u64 start, end;524 525	xe_gt_assert(gt, IS_SRIOV_VF(xe));526	xe_gt_assert(gt, !xe_gt_is_media_type(gt));527 528	if (!config->ggtt_size)529		return -ENODATA;530 531	/*532	 * VF can only use part of the GGTT as allocated by the PF:533	 *534	 *      WOPCM                                  GUC_GGTT_TOP535	 *      |<------------ Total GGTT size ------------------>|536	 *537	 *           VF GGTT base -->|<- size ->|538	 *539	 *      +--------------------+----------+-----------------+540	 *      |////////////////////|   block  |\\\\\\\\\\\\\\\\\|541	 *      +--------------------+----------+-----------------+542	 *543	 *      |<--- balloon[0] --->|<-- VF -->|<-- balloon[1] ->|544	 */545 546	start = xe_wopcm_size(xe);547	end = config->ggtt_base;548	if (end != start) {549		tile->sriov.vf.ggtt_balloon[0] = vf_balloon_ggtt_node(ggtt, start, end);550		if (IS_ERR(tile->sriov.vf.ggtt_balloon[0]))551			return PTR_ERR(tile->sriov.vf.ggtt_balloon[0]);552	}553 554	start = config->ggtt_base + config->ggtt_size;555	end = GUC_GGTT_TOP;556	if (end != start) {557		tile->sriov.vf.ggtt_balloon[1] = vf_balloon_ggtt_node(ggtt, start, end);558		if (IS_ERR(tile->sriov.vf.ggtt_balloon[1])) {559			xe_ggtt_node_remove_balloon(tile->sriov.vf.ggtt_balloon[0]);560			return PTR_ERR(tile->sriov.vf.ggtt_balloon[1]);561		}562	}563 564	return 0;565}566 567static void deballoon_ggtt(struct drm_device *drm, void *arg)568{569	struct xe_tile *tile = arg;570 571	xe_tile_assert(tile, IS_SRIOV_VF(tile_to_xe(tile)));572	xe_ggtt_node_remove_balloon(tile->sriov.vf.ggtt_balloon[1]);573	xe_ggtt_node_remove_balloon(tile->sriov.vf.ggtt_balloon[0]);574}575 576/**577 * xe_gt_sriov_vf_prepare_ggtt - Prepare a VF's GGTT configuration.578 * @gt: the &xe_gt579 *580 * This function is for VF use only.581 *582 * Return: 0 on success or a negative error code on failure.583 */584int xe_gt_sriov_vf_prepare_ggtt(struct xe_gt *gt)585{586	struct xe_tile *tile = gt_to_tile(gt);587	struct xe_device *xe = tile_to_xe(tile);588	int err;589 590	if (xe_gt_is_media_type(gt))591		return 0;592 593	err = vf_balloon_ggtt(gt);594	if (err)595		return err;596 597	return drmm_add_action_or_reset(&xe->drm, deballoon_ggtt, tile);598}599 600static int relay_action_handshake(struct xe_gt *gt, u32 *major, u32 *minor)601{602	u32 request[VF2PF_HANDSHAKE_REQUEST_MSG_LEN] = {603		FIELD_PREP(GUC_HXG_MSG_0_ORIGIN, GUC_HXG_ORIGIN_HOST) |604		FIELD_PREP(GUC_HXG_MSG_0_TYPE, GUC_HXG_TYPE_REQUEST) |605		FIELD_PREP(GUC_HXG_REQUEST_MSG_0_ACTION, GUC_RELAY_ACTION_VF2PF_HANDSHAKE),606		FIELD_PREP(VF2PF_HANDSHAKE_REQUEST_MSG_1_MAJOR, *major) |607		FIELD_PREP(VF2PF_HANDSHAKE_REQUEST_MSG_1_MINOR, *minor),608	};609	u32 response[VF2PF_HANDSHAKE_RESPONSE_MSG_LEN];610	int ret;611 612	xe_gt_assert(gt, IS_SRIOV_VF(gt_to_xe(gt)));613 614	ret = xe_guc_relay_send_to_pf(&gt->uc.guc.relay,615				      request, ARRAY_SIZE(request),616				      response, ARRAY_SIZE(response));617	if (unlikely(ret < 0))618		return ret;619 620	if (unlikely(ret != VF2PF_HANDSHAKE_RESPONSE_MSG_LEN))621		return -EPROTO;622 623	if (unlikely(FIELD_GET(VF2PF_HANDSHAKE_RESPONSE_MSG_0_MBZ, response[0])))624		return -EPROTO;625 626	*major = FIELD_GET(VF2PF_HANDSHAKE_RESPONSE_MSG_1_MAJOR, response[1]);627	*minor = FIELD_GET(VF2PF_HANDSHAKE_RESPONSE_MSG_1_MINOR, response[1]);628 629	return 0;630}631 632static void vf_connect_pf(struct xe_gt *gt, u16 major, u16 minor)633{634	xe_gt_assert(gt, IS_SRIOV_VF(gt_to_xe(gt)));635 636	gt->sriov.vf.pf_version.major = major;637	gt->sriov.vf.pf_version.minor = minor;638}639 640static void vf_disconnect_pf(struct xe_gt *gt)641{642	vf_connect_pf(gt, 0, 0);643}644 645static int vf_handshake_with_pf(struct xe_gt *gt)646{647	u32 major_wanted = GUC_RELAY_VERSION_LATEST_MAJOR;648	u32 minor_wanted = GUC_RELAY_VERSION_LATEST_MINOR;649	u32 major = major_wanted, minor = minor_wanted;650	int err;651 652	err = relay_action_handshake(gt, &major, &minor);653	if (unlikely(err))654		goto failed;655 656	if (!major && !minor) {657		err = -ENODATA;658		goto failed;659	}660 661	xe_gt_sriov_dbg(gt, "using VF/PF ABI %u.%u\n", major, minor);662	vf_connect_pf(gt, major, minor);663	return 0;664 665failed:666	xe_gt_sriov_err(gt, "Unable to confirm VF/PF ABI version %u.%u (%pe)\n",667			major, minor, ERR_PTR(err));668	vf_disconnect_pf(gt);669	return err;670}671 672/**673 * xe_gt_sriov_vf_connect - Establish connection with the PF driver.674 * @gt: the &xe_gt675 *676 * This function is for VF use only.677 *678 * Return: 0 on success or a negative error code on failure.679 */680int xe_gt_sriov_vf_connect(struct xe_gt *gt)681{682	int err;683 684	err = vf_handshake_with_pf(gt);685	if (unlikely(err))686		goto failed;687 688	return 0;689 690failed:691	xe_gt_sriov_err(gt, "Failed to get version info (%pe)\n", ERR_PTR(err));692	return err;693}694 695static bool vf_is_negotiated(struct xe_gt *gt, u16 major, u16 minor)696{697	xe_gt_assert(gt, IS_SRIOV_VF(gt_to_xe(gt)));698 699	return major == gt->sriov.vf.pf_version.major &&700	       minor <= gt->sriov.vf.pf_version.minor;701}702 703static int vf_prepare_runtime_info(struct xe_gt *gt, unsigned int num_regs)704{705	struct vf_runtime_reg *regs = gt->sriov.vf.runtime.regs;706	unsigned int regs_size = round_up(num_regs, 4);707	struct xe_device *xe = gt_to_xe(gt);708 709	xe_gt_assert(gt, IS_SRIOV_VF(xe));710 711	if (regs) {712		if (num_regs <= gt->sriov.vf.runtime.regs_size) {713			memset(regs, 0, num_regs * sizeof(*regs));714			gt->sriov.vf.runtime.num_regs = num_regs;715			return 0;716		}717 718		drmm_kfree(&xe->drm, regs);719		gt->sriov.vf.runtime.regs = NULL;720		gt->sriov.vf.runtime.num_regs = 0;721		gt->sriov.vf.runtime.regs_size = 0;722	}723 724	regs = drmm_kcalloc(&xe->drm, regs_size, sizeof(*regs), GFP_KERNEL);725	if (unlikely(!regs))726		return -ENOMEM;727 728	gt->sriov.vf.runtime.regs = regs;729	gt->sriov.vf.runtime.num_regs = num_regs;730	gt->sriov.vf.runtime.regs_size = regs_size;731	return 0;732}733 734static int vf_query_runtime_info(struct xe_gt *gt)735{736	u32 request[VF2PF_QUERY_RUNTIME_REQUEST_MSG_LEN];737	u32 response[VF2PF_QUERY_RUNTIME_RESPONSE_MSG_MIN_LEN + 32]; /* up to 16 regs */738	u32 limit = (ARRAY_SIZE(response) - VF2PF_QUERY_RUNTIME_RESPONSE_MSG_MIN_LEN) / 2;739	u32 count, remaining, num, i;740	u32 start = 0;741	int ret;742 743	xe_gt_assert(gt, IS_SRIOV_VF(gt_to_xe(gt)));744	xe_gt_assert(gt, limit);745 746	/* this is part of the 1.0 PF/VF ABI */747	if (!vf_is_negotiated(gt, 1, 0))748		return -ENOPKG;749 750	request[0] = FIELD_PREP(GUC_HXG_MSG_0_ORIGIN, GUC_HXG_ORIGIN_HOST) |751		     FIELD_PREP(GUC_HXG_MSG_0_TYPE, GUC_HXG_TYPE_REQUEST) |752		     FIELD_PREP(GUC_HXG_REQUEST_MSG_0_ACTION,753				GUC_RELAY_ACTION_VF2PF_QUERY_RUNTIME) |754		     FIELD_PREP(VF2PF_QUERY_RUNTIME_REQUEST_MSG_0_LIMIT, limit);755 756repeat:757	request[1] = FIELD_PREP(VF2PF_QUERY_RUNTIME_REQUEST_MSG_1_START, start);758	ret = xe_guc_relay_send_to_pf(&gt->uc.guc.relay,759				      request, ARRAY_SIZE(request),760				      response, ARRAY_SIZE(response));761	if (unlikely(ret < 0))762		goto failed;763 764	if (unlikely(ret < VF2PF_QUERY_RUNTIME_RESPONSE_MSG_MIN_LEN)) {765		ret = -EPROTO;766		goto failed;767	}768	if (unlikely((ret - VF2PF_QUERY_RUNTIME_RESPONSE_MSG_MIN_LEN) % 2)) {769		ret = -EPROTO;770		goto failed;771	}772 773	num = (ret - VF2PF_QUERY_RUNTIME_RESPONSE_MSG_MIN_LEN) / 2;774	count = FIELD_GET(VF2PF_QUERY_RUNTIME_RESPONSE_MSG_0_COUNT, response[0]);775	remaining = FIELD_GET(VF2PF_QUERY_RUNTIME_RESPONSE_MSG_1_REMAINING, response[1]);776 777	xe_gt_sriov_dbg_verbose(gt, "count=%u num=%u ret=%d start=%u remaining=%u\n",778				count, num, ret, start, remaining);779 780	if (unlikely(count != num)) {781		ret = -EPROTO;782		goto failed;783	}784 785	if (start == 0) {786		ret = vf_prepare_runtime_info(gt, num + remaining);787		if (unlikely(ret < 0))788			goto failed;789	} else if (unlikely(start + num > gt->sriov.vf.runtime.num_regs)) {790		ret = -EPROTO;791		goto failed;792	}793 794	for (i = 0; i < num; ++i) {795		struct vf_runtime_reg *reg = &gt->sriov.vf.runtime.regs[start + i];796 797		reg->offset = response[VF2PF_QUERY_RUNTIME_RESPONSE_MSG_MIN_LEN + 2 * i];798		reg->value = response[VF2PF_QUERY_RUNTIME_RESPONSE_MSG_MIN_LEN + 2 * i + 1];799	}800 801	if (remaining) {802		start += num;803		goto repeat;804	}805 806	return 0;807 808failed:809	vf_prepare_runtime_info(gt, 0);810	return ret;811}812 813static void vf_show_runtime_info(struct xe_gt *gt)814{815	struct vf_runtime_reg *vf_regs = gt->sriov.vf.runtime.regs;816	unsigned int size = gt->sriov.vf.runtime.num_regs;817 818	xe_gt_assert(gt, IS_SRIOV_VF(gt_to_xe(gt)));819 820	for (; size--; vf_regs++)821		xe_gt_sriov_dbg(gt, "runtime(%#x) = %#x\n",822				vf_regs->offset, vf_regs->value);823}824 825/**826 * xe_gt_sriov_vf_query_runtime - Query SR-IOV runtime data.827 * @gt: the &xe_gt828 *829 * This function is for VF use only.830 *831 * Return: 0 on success or a negative error code on failure.832 */833int xe_gt_sriov_vf_query_runtime(struct xe_gt *gt)834{835	int err;836 837	err = vf_query_runtime_info(gt);838	if (unlikely(err))839		goto failed;840 841	if (IS_ENABLED(CONFIG_DRM_XE_DEBUG))842		vf_show_runtime_info(gt);843 844	return 0;845 846failed:847	xe_gt_sriov_err(gt, "Failed to get runtime info (%pe)\n",848			ERR_PTR(err));849	return err;850}851 852static int vf_runtime_reg_cmp(const void *a, const void *b)853{854	const struct vf_runtime_reg *ra = a;855	const struct vf_runtime_reg *rb = b;856 857	return (int)ra->offset - (int)rb->offset;858}859 860static struct vf_runtime_reg *vf_lookup_reg(struct xe_gt *gt, u32 addr)861{862	struct xe_gt_sriov_vf_runtime *runtime = &gt->sriov.vf.runtime;863	struct vf_runtime_reg key = { .offset = addr };864 865	xe_gt_assert(gt, IS_SRIOV_VF(gt_to_xe(gt)));866 867	return bsearch(&key, runtime->regs, runtime->num_regs, sizeof(key),868		       vf_runtime_reg_cmp);869}870 871/**872 * xe_gt_sriov_vf_read32 - Get a register value from the runtime data.873 * @gt: the &xe_gt874 * @reg: the register to read875 *876 * This function is for VF use only.877 * This function shall be called after VF has connected to PF.878 * This function is dedicated for registers that VFs can't read directly.879 *880 * Return: register value obtained from the PF or 0 if not found.881 */882u32 xe_gt_sriov_vf_read32(struct xe_gt *gt, struct xe_reg reg)883{884	u32 addr = xe_mmio_adjusted_addr(gt, reg.addr);885	struct vf_runtime_reg *rr;886 887	xe_gt_assert(gt, IS_SRIOV_VF(gt_to_xe(gt)));888	xe_gt_assert(gt, gt->sriov.vf.pf_version.major);889	xe_gt_assert(gt, !reg.vf);890 891	if (reg.addr == GMD_ID.addr) {892		xe_gt_sriov_dbg_verbose(gt, "gmdid(%#x) = %#x\n",893					addr, gt->sriov.vf.runtime.gmdid);894		return gt->sriov.vf.runtime.gmdid;895	}896 897	rr = vf_lookup_reg(gt, addr);898	if (!rr) {899		xe_gt_WARN(gt, IS_ENABLED(CONFIG_DRM_XE_DEBUG),900			   "VF is trying to read an inaccessible register %#x+%#x\n",901			   reg.addr, addr - reg.addr);902		return 0;903	}904 905	xe_gt_sriov_dbg_verbose(gt, "runtime[%#x] = %#x\n", addr, rr->value);906	return rr->value;907}908 909/**910 * xe_gt_sriov_vf_write32 - Handle a write to an inaccessible register.911 * @gt: the &xe_gt912 * @reg: the register to write913 * @val: value to write914 *915 * This function is for VF use only.916 * Currently it will trigger a WARN if running on debug build.917 */918void xe_gt_sriov_vf_write32(struct xe_gt *gt, struct xe_reg reg, u32 val)919{920	u32 addr = xe_mmio_adjusted_addr(gt, reg.addr);921 922	xe_gt_assert(gt, IS_SRIOV_VF(gt_to_xe(gt)));923	xe_gt_assert(gt, !reg.vf);924 925	/*926	 * In the future, we may want to handle selected writes to inaccessible927	 * registers in some custom way, but for now let's just log a warning928	 * about such attempt, as likely we might be doing something wrong.929	 */930	xe_gt_WARN(gt, IS_ENABLED(CONFIG_DRM_XE_DEBUG),931		   "VF is trying to write %#x to an inaccessible register %#x+%#x\n",932		   val, reg.addr, addr - reg.addr);933}934 935/**936 * xe_gt_sriov_vf_print_config - Print VF self config.937 * @gt: the &xe_gt938 * @p: the &drm_printer939 *940 * This function is for VF use only.941 */942void xe_gt_sriov_vf_print_config(struct xe_gt *gt, struct drm_printer *p)943{944	struct xe_gt_sriov_vf_selfconfig *config = &gt->sriov.vf.self_config;945	struct xe_device *xe = gt_to_xe(gt);946	char buf[10];947 948	xe_gt_assert(gt, IS_SRIOV_VF(gt_to_xe(gt)));949 950	drm_printf(p, "GGTT range:\t%#llx-%#llx\n",951		   config->ggtt_base,952		   config->ggtt_base + config->ggtt_size - 1);953 954	string_get_size(config->ggtt_size, 1, STRING_UNITS_2, buf, sizeof(buf));955	drm_printf(p, "GGTT size:\t%llu (%s)\n", config->ggtt_size, buf);956 957	if (IS_DGFX(xe) && !xe_gt_is_media_type(gt)) {958		string_get_size(config->lmem_size, 1, STRING_UNITS_2, buf, sizeof(buf));959		drm_printf(p, "LMEM size:\t%llu (%s)\n", config->lmem_size, buf);960	}961 962	drm_printf(p, "GuC contexts:\t%u\n", config->num_ctxs);963	drm_printf(p, "GuC doorbells:\t%u\n", config->num_dbs);964}965 966/**967 * xe_gt_sriov_vf_print_runtime - Print VF's runtime regs received from PF.968 * @gt: the &xe_gt969 * @p: the &drm_printer970 *971 * This function is for VF use only.972 */973void xe_gt_sriov_vf_print_runtime(struct xe_gt *gt, struct drm_printer *p)974{975	struct vf_runtime_reg *vf_regs = gt->sriov.vf.runtime.regs;976	unsigned int size = gt->sriov.vf.runtime.num_regs;977 978	xe_gt_assert(gt, IS_SRIOV_VF(gt_to_xe(gt)));979 980	for (; size--; vf_regs++)981		drm_printf(p, "%#x = %#x\n", vf_regs->offset, vf_regs->value);982}983 984/**985 * xe_gt_sriov_vf_print_version - Print VF ABI versions.986 * @gt: the &xe_gt987 * @p: the &drm_printer988 *989 * This function is for VF use only.990 */991void xe_gt_sriov_vf_print_version(struct xe_gt *gt, struct drm_printer *p)992{993	struct xe_gt_sriov_vf_guc_version *guc_version = &gt->sriov.vf.guc_version;994	struct xe_gt_sriov_vf_relay_version *pf_version = &gt->sriov.vf.pf_version;995	u32 branch, major, minor;996 997	xe_gt_assert(gt, IS_SRIOV_VF(gt_to_xe(gt)));998 999	drm_printf(p, "GuC ABI:\n");1000 1001	vf_minimum_guc_version(gt, &branch, &major, &minor);1002	drm_printf(p, "\tbase:\t%u.%u.%u.*\n", branch, major, minor);1003 1004	vf_wanted_guc_version(gt, &branch, &major, &minor);1005	drm_printf(p, "\twanted:\t%u.%u.%u.*\n", branch, major, minor);1006 1007	drm_printf(p, "\thandshake:\t%u.%u.%u.%u\n",1008		   guc_version->branch, guc_version->major,1009		   guc_version->minor, guc_version->patch);1010 1011	drm_printf(p, "PF ABI:\n");1012 1013	drm_printf(p, "\tbase:\t%u.%u\n",1014		   GUC_RELAY_VERSION_BASE_MAJOR, GUC_RELAY_VERSION_BASE_MINOR);1015	drm_printf(p, "\twanted:\t%u.%u\n",1016		   GUC_RELAY_VERSION_LATEST_MAJOR, GUC_RELAY_VERSION_LATEST_MINOR);1017	drm_printf(p, "\thandshake:\t%u.%u\n",1018		   pf_version->major, pf_version->minor);1019}1020