brintos

brintos / linux-shallow public Read only

0
0
Text · 16.2 KiB · 0e23b7e Raw
551 lines · c
1// SPDX-License-Identifier: MIT2/*3 * Copyright © 2023-2024 Intel Corporation4 */5 6#include <drm/drm_managed.h>7 8#include "abi/guc_actions_sriov_abi.h"9#include "abi/guc_relay_actions_abi.h"10 11#include "regs/xe_gt_regs.h"12#include "regs/xe_guc_regs.h"13#include "regs/xe_regs.h"14 15#include "xe_mmio.h"16#include "xe_gt_sriov_printk.h"17#include "xe_gt_sriov_pf_helpers.h"18#include "xe_gt_sriov_pf_service.h"19#include "xe_gt_sriov_pf_service_types.h"20#include "xe_guc_ct.h"21#include "xe_guc_hxg_helpers.h"22 23static void pf_init_versions(struct xe_gt *gt)24{25	BUILD_BUG_ON(!GUC_RELAY_VERSION_BASE_MAJOR && !GUC_RELAY_VERSION_BASE_MINOR);26	BUILD_BUG_ON(GUC_RELAY_VERSION_BASE_MAJOR > GUC_RELAY_VERSION_LATEST_MAJOR);27 28	/* base versions may differ between platforms */29	gt->sriov.pf.service.version.base.major = GUC_RELAY_VERSION_BASE_MAJOR;30	gt->sriov.pf.service.version.base.minor = GUC_RELAY_VERSION_BASE_MINOR;31 32	/* latest version is same for all platforms */33	gt->sriov.pf.service.version.latest.major = GUC_RELAY_VERSION_LATEST_MAJOR;34	gt->sriov.pf.service.version.latest.minor = GUC_RELAY_VERSION_LATEST_MINOR;35}36 37/* Return: 0 on success or a negative error code on failure. */38static int pf_negotiate_version(struct xe_gt *gt,39				u32 wanted_major, u32 wanted_minor,40				u32 *major, u32 *minor)41{42	struct xe_gt_sriov_pf_service_version base = gt->sriov.pf.service.version.base;43	struct xe_gt_sriov_pf_service_version latest = gt->sriov.pf.service.version.latest;44 45	xe_gt_assert(gt, base.major);46	xe_gt_assert(gt, base.major <= latest.major);47	xe_gt_assert(gt, (base.major < latest.major) || (base.minor <= latest.minor));48 49	/* VF doesn't care - return our latest  */50	if (wanted_major == VF2PF_HANDSHAKE_MAJOR_ANY &&51	    wanted_minor == VF2PF_HANDSHAKE_MINOR_ANY) {52		*major = latest.major;53		*minor = latest.minor;54		return 0;55	}56 57	/* VF wants newer than our - return our latest  */58	if (wanted_major > latest.major) {59		*major = latest.major;60		*minor = latest.minor;61		return 0;62	}63 64	/* VF wants older than min required - reject */65	if (wanted_major < base.major ||66	    (wanted_major == base.major && wanted_minor < base.minor)) {67		return -EPERM;68	}69 70	/* previous major - return wanted, as we should still support it */71	if (wanted_major < latest.major) {72		/* XXX: we are not prepared for multi-versions yet */73		xe_gt_assert(gt, base.major == latest.major);74		return -ENOPKG;75	}76 77	/* same major - return common minor */78	*major = wanted_major;79	*minor = min_t(u32, latest.minor, wanted_minor);80	return 0;81}82 83static void pf_connect(struct xe_gt *gt, u32 vfid, u32 major, u32 minor)84{85	xe_gt_sriov_pf_assert_vfid(gt, vfid);86	xe_gt_assert(gt, major || minor);87 88	gt->sriov.pf.vfs[vfid].version.major = major;89	gt->sriov.pf.vfs[vfid].version.minor = minor;90}91 92static void pf_disconnect(struct xe_gt *gt, u32 vfid)93{94	xe_gt_sriov_pf_assert_vfid(gt, vfid);95 96	gt->sriov.pf.vfs[vfid].version.major = 0;97	gt->sriov.pf.vfs[vfid].version.minor = 0;98}99 100static bool pf_is_negotiated(struct xe_gt *gt, u32 vfid, u32 major, u32 minor)101{102	xe_gt_sriov_pf_assert_vfid(gt, vfid);103 104	return major == gt->sriov.pf.vfs[vfid].version.major &&105	       minor <= gt->sriov.pf.vfs[vfid].version.minor;106}107 108static const struct xe_reg tgl_runtime_regs[] = {109	RPM_CONFIG0,			/* _MMIO(0x0d00) */110	MIRROR_FUSE3,			/* _MMIO(0x9118) */111	XELP_EU_ENABLE,			/* _MMIO(0x9134) */112	XELP_GT_SLICE_ENABLE,		/* _MMIO(0x9138) */113	XELP_GT_GEOMETRY_DSS_ENABLE,	/* _MMIO(0x913c) */114	GT_VEBOX_VDBOX_DISABLE,		/* _MMIO(0x9140) */115	CTC_MODE,			/* _MMIO(0xa26c) */116	HUC_KERNEL_LOAD_INFO,		/* _MMIO(0xc1dc) */117	TIMESTAMP_OVERRIDE,		/* _MMIO(0x44074) */118};119 120static const struct xe_reg ats_m_runtime_regs[] = {121	RPM_CONFIG0,			/* _MMIO(0x0d00) */122	MIRROR_FUSE3,			/* _MMIO(0x9118) */123	MIRROR_FUSE1,			/* _MMIO(0x911c) */124	XELP_EU_ENABLE,			/* _MMIO(0x9134) */125	XELP_GT_GEOMETRY_DSS_ENABLE,	/* _MMIO(0x913c) */126	GT_VEBOX_VDBOX_DISABLE,		/* _MMIO(0x9140) */127	XEHP_GT_COMPUTE_DSS_ENABLE,	/* _MMIO(0x9144) */128	CTC_MODE,			/* _MMIO(0xa26c) */129	HUC_KERNEL_LOAD_INFO,		/* _MMIO(0xc1dc) */130	TIMESTAMP_OVERRIDE,		/* _MMIO(0x44074) */131};132 133static const struct xe_reg pvc_runtime_regs[] = {134	RPM_CONFIG0,			/* _MMIO(0x0d00) */135	MIRROR_FUSE3,			/* _MMIO(0x9118) */136	XELP_EU_ENABLE,			/* _MMIO(0x9134) */137	XELP_GT_GEOMETRY_DSS_ENABLE,	/* _MMIO(0x913c) */138	GT_VEBOX_VDBOX_DISABLE,		/* _MMIO(0x9140) */139	XEHP_GT_COMPUTE_DSS_ENABLE,	/* _MMIO(0x9144) */140	XEHPC_GT_COMPUTE_DSS_ENABLE_EXT,/* _MMIO(0x9148) */141	CTC_MODE,			/* _MMIO(0xA26C) */142	HUC_KERNEL_LOAD_INFO,		/* _MMIO(0xc1dc) */143	TIMESTAMP_OVERRIDE,		/* _MMIO(0x44074) */144};145 146static const struct xe_reg ver_1270_runtime_regs[] = {147	RPM_CONFIG0,			/* _MMIO(0x0d00) */148	XEHP_FUSE4,			/* _MMIO(0x9114) */149	MIRROR_FUSE3,			/* _MMIO(0x9118) */150	MIRROR_FUSE1,			/* _MMIO(0x911c) */151	XELP_EU_ENABLE,			/* _MMIO(0x9134) */152	XELP_GT_GEOMETRY_DSS_ENABLE,	/* _MMIO(0x913c) */153	GT_VEBOX_VDBOX_DISABLE,		/* _MMIO(0x9140) */154	XEHP_GT_COMPUTE_DSS_ENABLE,	/* _MMIO(0x9144) */155	XEHPC_GT_COMPUTE_DSS_ENABLE_EXT,/* _MMIO(0x9148) */156	CTC_MODE,			/* _MMIO(0xa26c) */157	HUC_KERNEL_LOAD_INFO,		/* _MMIO(0xc1dc) */158	TIMESTAMP_OVERRIDE,		/* _MMIO(0x44074) */159};160 161static const struct xe_reg ver_2000_runtime_regs[] = {162	RPM_CONFIG0,			/* _MMIO(0x0d00) */163	XEHP_FUSE4,			/* _MMIO(0x9114) */164	MIRROR_FUSE3,			/* _MMIO(0x9118) */165	MIRROR_FUSE1,			/* _MMIO(0x911c) */166	XELP_EU_ENABLE,			/* _MMIO(0x9134) */167	XELP_GT_GEOMETRY_DSS_ENABLE,	/* _MMIO(0x913c) */168	GT_VEBOX_VDBOX_DISABLE,		/* _MMIO(0x9140) */169	XEHP_GT_COMPUTE_DSS_ENABLE,	/* _MMIO(0x9144) */170	XEHPC_GT_COMPUTE_DSS_ENABLE_EXT,/* _MMIO(0x9148) */171	XE2_GT_COMPUTE_DSS_2,		/* _MMIO(0x914c) */172	XE2_GT_GEOMETRY_DSS_1,		/* _MMIO(0x9150) */173	XE2_GT_GEOMETRY_DSS_2,		/* _MMIO(0x9154) */174	CTC_MODE,			/* _MMIO(0xa26c) */175	HUC_KERNEL_LOAD_INFO,		/* _MMIO(0xc1dc) */176	TIMESTAMP_OVERRIDE,		/* _MMIO(0x44074) */177};178 179static const struct xe_reg *pick_runtime_regs(struct xe_device *xe, unsigned int *count)180{181	const struct xe_reg *regs;182 183	if (GRAPHICS_VERx100(xe) >= 2000) {184		*count = ARRAY_SIZE(ver_2000_runtime_regs);185		regs = ver_2000_runtime_regs;186	} else if (GRAPHICS_VERx100(xe) >= 1270) {187		*count = ARRAY_SIZE(ver_1270_runtime_regs);188		regs = ver_1270_runtime_regs;189	} else if (GRAPHICS_VERx100(xe) == 1260) {190		*count = ARRAY_SIZE(pvc_runtime_regs);191		regs = pvc_runtime_regs;192	} else if (GRAPHICS_VERx100(xe) == 1255) {193		*count = ARRAY_SIZE(ats_m_runtime_regs);194		regs = ats_m_runtime_regs;195	} else if (GRAPHICS_VERx100(xe) == 1200) {196		*count = ARRAY_SIZE(tgl_runtime_regs);197		regs = tgl_runtime_regs;198	} else {199		regs = ERR_PTR(-ENOPKG);200		*count = 0;201	}202 203	return regs;204}205 206static int pf_alloc_runtime_info(struct xe_gt *gt)207{208	struct xe_device *xe = gt_to_xe(gt);209	const struct xe_reg *regs;210	unsigned int size;211	u32 *values;212 213	xe_gt_assert(gt, IS_SRIOV_PF(xe));214	xe_gt_assert(gt, !gt->sriov.pf.service.runtime.size);215	xe_gt_assert(gt, !gt->sriov.pf.service.runtime.regs);216	xe_gt_assert(gt, !gt->sriov.pf.service.runtime.values);217 218	regs = pick_runtime_regs(xe, &size);219	if (IS_ERR(regs))220		return PTR_ERR(regs);221 222	if (unlikely(!size))223		return 0;224 225	values = drmm_kcalloc(&xe->drm, size, sizeof(u32), GFP_KERNEL);226	if (!values)227		return -ENOMEM;228 229	gt->sriov.pf.service.runtime.size = size;230	gt->sriov.pf.service.runtime.regs = regs;231	gt->sriov.pf.service.runtime.values = values;232 233	return 0;234}235 236static void read_many(struct xe_gt *gt, unsigned int count,237		      const struct xe_reg *regs, u32 *values)238{239	while (count--)240		*values++ = xe_mmio_read32(gt, *regs++);241}242 243static void pf_prepare_runtime_info(struct xe_gt *gt)244{245	const struct xe_reg *regs;246	unsigned int size;247	u32 *values;248 249	if (!gt->sriov.pf.service.runtime.size)250		return;251 252	size = gt->sriov.pf.service.runtime.size;253	regs = gt->sriov.pf.service.runtime.regs;254	values = gt->sriov.pf.service.runtime.values;255 256	read_many(gt, size, regs, values);257 258	if (IS_ENABLED(CONFIG_DRM_XE_DEBUG_SRIOV)) {259		struct drm_printer p = xe_gt_info_printer(gt);260 261		xe_gt_sriov_pf_service_print_runtime(gt, &p);262	}263}264 265/**266 * xe_gt_sriov_pf_service_init - Early initialization of the GT SR-IOV PF services.267 * @gt: the &xe_gt to initialize268 *269 * Performs early initialization of the GT SR-IOV PF services, including preparation270 * of the runtime info that will be shared with VFs.271 *272 * This function can only be called on PF.273 */274int xe_gt_sriov_pf_service_init(struct xe_gt *gt)275{276	int err;277 278	pf_init_versions(gt);279 280	err = pf_alloc_runtime_info(gt);281	if (unlikely(err))282		goto failed;283 284	return 0;285failed:286	xe_gt_sriov_err(gt, "Failed to initialize service (%pe)\n", ERR_PTR(err));287	return err;288}289 290/**291 * xe_gt_sriov_pf_service_update - Update PF SR-IOV services.292 * @gt: the &xe_gt to update293 *294 * Updates runtime data shared with VFs.295 *296 * This function can be called more than once.297 * This function can only be called on PF.298 */299void xe_gt_sriov_pf_service_update(struct xe_gt *gt)300{301	pf_prepare_runtime_info(gt);302}303 304/**305 * xe_gt_sriov_pf_service_reset - Reset a connection with the VF.306 * @gt: the &xe_gt307 * @vfid: the VF identifier308 *309 * Reset a VF driver negotiated VF/PF ABI version.310 * After that point, the VF driver will have to perform new version handshake311 * to continue use of the PF services again.312 *313 * This function can only be called on PF.314 */315void xe_gt_sriov_pf_service_reset(struct xe_gt *gt, unsigned int vfid)316{317	pf_disconnect(gt, vfid);318}319 320/* Return: 0 on success or a negative error code on failure. */321static int pf_process_handshake(struct xe_gt *gt, u32 vfid,322				u32 wanted_major, u32 wanted_minor,323				u32 *major, u32 *minor)324{325	int err;326 327	xe_gt_sriov_dbg_verbose(gt, "VF%u wants ABI version %u.%u\n",328				vfid, wanted_major, wanted_minor);329 330	err = pf_negotiate_version(gt, wanted_major, wanted_minor, major, minor);331 332	if (err < 0) {333		xe_gt_sriov_notice(gt, "VF%u failed to negotiate ABI %u.%u (%pe)\n",334				   vfid, wanted_major, wanted_minor, ERR_PTR(err));335		pf_disconnect(gt, vfid);336	} else {337		xe_gt_sriov_dbg(gt, "VF%u negotiated ABI version %u.%u\n",338				vfid, *major, *minor);339		pf_connect(gt, vfid, *major, *minor);340	}341 342	return 0;343}344 345/* Return: length of the response message or a negative error code on failure. */346static int pf_process_handshake_msg(struct xe_gt *gt, u32 origin,347				    const u32 *request, u32 len, u32 *response, u32 size)348{349	u32 wanted_major, wanted_minor;350	u32 major, minor;351	u32 mbz;352	int err;353 354	if (unlikely(len != VF2PF_HANDSHAKE_REQUEST_MSG_LEN))355		return -EMSGSIZE;356 357	mbz = FIELD_GET(VF2PF_HANDSHAKE_REQUEST_MSG_0_MBZ, request[0]);358	if (unlikely(mbz))359		return -EPFNOSUPPORT;360 361	wanted_major = FIELD_GET(VF2PF_HANDSHAKE_REQUEST_MSG_1_MAJOR, request[1]);362	wanted_minor = FIELD_GET(VF2PF_HANDSHAKE_REQUEST_MSG_1_MINOR, request[1]);363 364	err = pf_process_handshake(gt, origin, wanted_major, wanted_minor, &major, &minor);365	if (err < 0)366		return err;367 368	xe_gt_assert(gt, major || minor);369	xe_gt_assert(gt, size >= VF2PF_HANDSHAKE_RESPONSE_MSG_LEN);370 371	response[0] = FIELD_PREP(GUC_HXG_MSG_0_ORIGIN, GUC_HXG_ORIGIN_HOST) |372		      FIELD_PREP(GUC_HXG_MSG_0_TYPE, GUC_HXG_TYPE_RESPONSE_SUCCESS) |373		      FIELD_PREP(GUC_HXG_RESPONSE_MSG_0_DATA0, 0);374	response[1] = FIELD_PREP(VF2PF_HANDSHAKE_RESPONSE_MSG_1_MAJOR, major) |375		      FIELD_PREP(VF2PF_HANDSHAKE_RESPONSE_MSG_1_MINOR, minor);376 377	return VF2PF_HANDSHAKE_RESPONSE_MSG_LEN;378}379 380struct reg_data {381	u32 offset;382	u32 value;383} __packed;384static_assert(hxg_sizeof(struct reg_data) == 2);385 386/* Return: number of entries copied or negative error code on failure. */387static int pf_service_runtime_query(struct xe_gt *gt, u32 start, u32 limit,388				    struct reg_data *data, u32 *remaining)389{390	struct xe_gt_sriov_pf_service_runtime_regs *runtime;391	unsigned int count, i;392	u32 addr;393 394	xe_gt_assert(gt, IS_SRIOV_PF(gt_to_xe(gt)));395 396	runtime = &gt->sriov.pf.service.runtime;397 398	if (start > runtime->size)399		return -ERANGE;400 401	count = min_t(u32, runtime->size - start, limit);402 403	for (i = 0; i < count; ++i, ++data) {404		addr = runtime->regs[start + i].addr;405		data->offset = xe_mmio_adjusted_addr(gt, addr);406		data->value = runtime->values[start + i];407	}408 409	*remaining = runtime->size - start - count;410	return count;411}412 413/* Return: length of the response message or a negative error code on failure. */414static int pf_process_runtime_query_msg(struct xe_gt *gt, u32 origin,415					const u32 *msg, u32 msg_len, u32 *response, u32 resp_size)416{417	const u32 chunk_size = hxg_sizeof(struct reg_data);418	struct reg_data *reg_data_buf;419	u32 limit, start, max_chunks;420	u32 remaining = 0;421	int ret;422 423	if (!pf_is_negotiated(gt, origin, 1, 0))424		return -EACCES;425	if (unlikely(msg_len > VF2PF_QUERY_RUNTIME_REQUEST_MSG_LEN))426		return -EMSGSIZE;427	if (unlikely(msg_len < VF2PF_QUERY_RUNTIME_REQUEST_MSG_LEN))428		return -EPROTO;429	if (unlikely(resp_size < VF2PF_QUERY_RUNTIME_RESPONSE_MSG_MIN_LEN))430		return -EINVAL;431 432	limit = FIELD_GET(VF2PF_QUERY_RUNTIME_REQUEST_MSG_0_LIMIT, msg[0]);433	start = FIELD_GET(VF2PF_QUERY_RUNTIME_REQUEST_MSG_1_START, msg[1]);434 435	resp_size = min_t(u32, resp_size, VF2PF_QUERY_RUNTIME_RESPONSE_MSG_MAX_LEN);436	max_chunks = (resp_size - VF2PF_QUERY_RUNTIME_RESPONSE_MSG_MIN_LEN) / chunk_size;437	limit = limit == VF2PF_QUERY_RUNTIME_NO_LIMIT ? max_chunks : min_t(u32, max_chunks, limit);438	reg_data_buf = (void *)(response + VF2PF_QUERY_RUNTIME_RESPONSE_MSG_MIN_LEN);439 440	ret = pf_service_runtime_query(gt, start, limit, reg_data_buf, &remaining);441	if (ret < 0)442		return ret;443 444	response[0] = FIELD_PREP(GUC_HXG_MSG_0_ORIGIN, GUC_HXG_ORIGIN_HOST) |445		      FIELD_PREP(GUC_HXG_MSG_0_TYPE, GUC_HXG_TYPE_RESPONSE_SUCCESS) |446		      FIELD_PREP(VF2PF_QUERY_RUNTIME_RESPONSE_MSG_0_COUNT, ret);447	response[1] = FIELD_PREP(VF2PF_QUERY_RUNTIME_RESPONSE_MSG_1_REMAINING, remaining);448 449	return VF2PF_QUERY_RUNTIME_RESPONSE_MSG_MIN_LEN + ret * hxg_sizeof(struct reg_data);450}451 452/**453 * xe_gt_sriov_pf_service_process_request - Service GT level SR-IOV request message from the VF.454 * @gt: the &xe_gt that provides the service455 * @origin: VF number that is requesting the service456 * @msg: request message457 * @msg_len: length of the request message (in dwords)458 * @response: placeholder for the response message459 * @resp_size: length of the response message buffer (in dwords)460 *461 * This function processes `Relay Message`_ request from the VF.462 *463 * Return: length of the response message or a negative error code on failure.464 */465int xe_gt_sriov_pf_service_process_request(struct xe_gt *gt, u32 origin,466					   const u32 *msg, u32 msg_len,467					   u32 *response, u32 resp_size)468{469	u32 action, data __maybe_unused;470	int ret;471 472	xe_gt_assert(gt, msg_len >= GUC_HXG_MSG_MIN_LEN);473	xe_gt_assert(gt, FIELD_GET(GUC_HXG_MSG_0_TYPE, msg[0]) == GUC_HXG_TYPE_REQUEST);474 475	action = FIELD_GET(GUC_HXG_REQUEST_MSG_0_ACTION, msg[0]);476	data = FIELD_GET(GUC_HXG_REQUEST_MSG_0_DATA0, msg[0]);477	xe_gt_sriov_dbg_verbose(gt, "service action %#x:%u from VF%u\n",478				action, data, origin);479 480	switch (action) {481	case GUC_RELAY_ACTION_VF2PF_HANDSHAKE:482		ret = pf_process_handshake_msg(gt, origin, msg, msg_len, response, resp_size);483		break;484	case GUC_RELAY_ACTION_VF2PF_QUERY_RUNTIME:485		ret = pf_process_runtime_query_msg(gt, origin, msg, msg_len, response, resp_size);486		break;487	default:488		ret = -EOPNOTSUPP;489		break;490	}491 492	return ret;493}494 495/**496 * xe_gt_sriov_pf_service_print_runtime - Print PF runtime data shared with VFs.497 * @gt: the &xe_gt498 * @p: the &drm_printer499 *500 * This function is for PF use only.501 */502int xe_gt_sriov_pf_service_print_runtime(struct xe_gt *gt, struct drm_printer *p)503{504	const struct xe_reg *regs;505	unsigned int size;506	u32 *values;507 508	xe_gt_assert(gt, IS_SRIOV_PF(gt_to_xe(gt)));509 510	size = gt->sriov.pf.service.runtime.size;511	regs = gt->sriov.pf.service.runtime.regs;512	values = gt->sriov.pf.service.runtime.values;513 514	for (; size--; regs++, values++) {515		drm_printf(p, "reg[%#x] = %#x\n",516			   xe_mmio_adjusted_addr(gt, regs->addr), *values);517	}518 519	return 0;520}521 522/**523 * xe_gt_sriov_pf_service_print_version - Print ABI versions negotiated with VFs.524 * @gt: the &xe_gt525 * @p: the &drm_printer526 *527 * This function is for PF use only.528 */529int xe_gt_sriov_pf_service_print_version(struct xe_gt *gt, struct drm_printer *p)530{531	struct xe_device *xe = gt_to_xe(gt);532	unsigned int n, total_vfs = xe_sriov_pf_get_totalvfs(xe);533	struct xe_gt_sriov_pf_service_version *version;534 535	xe_gt_assert(gt, IS_SRIOV_PF(xe));536 537	for (n = 1; n <= total_vfs; n++) {538		version = &gt->sriov.pf.vfs[n].version;539		if (!version->major && !version->minor)540			continue;541 542		drm_printf(p, "VF%u:\t%u.%u\n", n, version->major, version->minor);543	}544 545	return 0;546}547 548#if IS_BUILTIN(CONFIG_DRM_XE_KUNIT_TEST)549#include "tests/xe_gt_sriov_pf_service_test.c"550#endif551