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 = >->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 = >->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