1 // SPDX-License-Identifier: MIT 2 /* 3 * Copyright © 2023-2024 Intel Corporation 4 */ 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 #include "xe_sriov_pf_service.h" 23 24 static const struct xe_reg tgl_runtime_regs[] = { 25 RPM_CONFIG0, /* _MMIO(0x0d00) */ 26 MIRROR_FUSE3, /* _MMIO(0x9118) */ 27 XELP_EU_ENABLE, /* _MMIO(0x9134) */ 28 XELP_GT_SLICE_ENABLE, /* _MMIO(0x9138) */ 29 XELP_GT_GEOMETRY_DSS_ENABLE, /* _MMIO(0x913c) */ 30 GT_VEBOX_VDBOX_DISABLE, /* _MMIO(0x9140) */ 31 HUC_KERNEL_LOAD_INFO, /* _MMIO(0xc1dc) */ 32 }; 33 34 static const struct xe_reg ats_m_runtime_regs[] = { 35 RPM_CONFIG0, /* _MMIO(0x0d00) */ 36 MIRROR_FUSE3, /* _MMIO(0x9118) */ 37 MIRROR_FUSE1, /* _MMIO(0x911c) */ 38 XELP_EU_ENABLE, /* _MMIO(0x9134) */ 39 XELP_GT_GEOMETRY_DSS_ENABLE, /* _MMIO(0x913c) */ 40 GT_VEBOX_VDBOX_DISABLE, /* _MMIO(0x9140) */ 41 XEHP_GT_COMPUTE_DSS_ENABLE, /* _MMIO(0x9144) */ 42 HUC_KERNEL_LOAD_INFO, /* _MMIO(0xc1dc) */ 43 }; 44 45 static const struct xe_reg pvc_runtime_regs[] = { 46 RPM_CONFIG0, /* _MMIO(0x0d00) */ 47 MIRROR_FUSE3, /* _MMIO(0x9118) */ 48 XELP_EU_ENABLE, /* _MMIO(0x9134) */ 49 XELP_GT_GEOMETRY_DSS_ENABLE, /* _MMIO(0x913c) */ 50 GT_VEBOX_VDBOX_DISABLE, /* _MMIO(0x9140) */ 51 XEHP_GT_COMPUTE_DSS_ENABLE, /* _MMIO(0x9144) */ 52 XEHPC_GT_COMPUTE_DSS_ENABLE_EXT,/* _MMIO(0x9148) */ 53 HUC_KERNEL_LOAD_INFO, /* _MMIO(0xc1dc) */ 54 }; 55 56 static const struct xe_reg ver_1270_runtime_regs[] = { 57 RPM_CONFIG0, /* _MMIO(0x0d00) */ 58 XEHP_FUSE4, /* _MMIO(0x9114) */ 59 MIRROR_FUSE3, /* _MMIO(0x9118) */ 60 MIRROR_FUSE1, /* _MMIO(0x911c) */ 61 XELP_EU_ENABLE, /* _MMIO(0x9134) */ 62 XELP_GT_GEOMETRY_DSS_ENABLE, /* _MMIO(0x913c) */ 63 GT_VEBOX_VDBOX_DISABLE, /* _MMIO(0x9140) */ 64 XEHP_GT_COMPUTE_DSS_ENABLE, /* _MMIO(0x9144) */ 65 XEHPC_GT_COMPUTE_DSS_ENABLE_EXT,/* _MMIO(0x9148) */ 66 HUC_KERNEL_LOAD_INFO, /* _MMIO(0xc1dc) */ 67 }; 68 69 static const struct xe_reg ver_2000_runtime_regs[] = { 70 RPM_CONFIG0, /* _MMIO(0x0d00) */ 71 XEHP_FUSE4, /* _MMIO(0x9114) */ 72 MIRROR_FUSE3, /* _MMIO(0x9118) */ 73 MIRROR_FUSE1, /* _MMIO(0x911c) */ 74 XELP_EU_ENABLE, /* _MMIO(0x9134) */ 75 XELP_GT_GEOMETRY_DSS_ENABLE, /* _MMIO(0x913c) */ 76 GT_VEBOX_VDBOX_DISABLE, /* _MMIO(0x9140) */ 77 XEHP_GT_COMPUTE_DSS_ENABLE, /* _MMIO(0x9144) */ 78 XEHPC_GT_COMPUTE_DSS_ENABLE_EXT,/* _MMIO(0x9148) */ 79 XE2_GT_COMPUTE_DSS_2, /* _MMIO(0x914c) */ 80 XE2_GT_GEOMETRY_DSS_1, /* _MMIO(0x9150) */ 81 XE2_GT_GEOMETRY_DSS_2, /* _MMIO(0x9154) */ 82 HUC_KERNEL_LOAD_INFO, /* _MMIO(0xc1dc) */ 83 }; 84 85 static const struct xe_reg ver_3000_runtime_regs[] = { 86 RPM_CONFIG0, /* _MMIO(0x0d00) */ 87 XEHP_FUSE4, /* _MMIO(0x9114) */ 88 MIRROR_FUSE3, /* _MMIO(0x9118) */ 89 MIRROR_FUSE1, /* _MMIO(0x911c) */ 90 MIRROR_L3BANK_ENABLE, /* _MMIO(0x9130) */ 91 XELP_EU_ENABLE, /* _MMIO(0x9134) */ 92 XELP_GT_GEOMETRY_DSS_ENABLE, /* _MMIO(0x913c) */ 93 GT_VEBOX_VDBOX_DISABLE, /* _MMIO(0x9140) */ 94 XEHP_GT_COMPUTE_DSS_ENABLE, /* _MMIO(0x9144) */ 95 XEHPC_GT_COMPUTE_DSS_ENABLE_EXT,/* _MMIO(0x9148) */ 96 XE2_GT_COMPUTE_DSS_2, /* _MMIO(0x914c) */ 97 XE2_GT_GEOMETRY_DSS_1, /* _MMIO(0x9150) */ 98 XE2_GT_GEOMETRY_DSS_2, /* _MMIO(0x9154) */ 99 HUC_KERNEL_LOAD_INFO, /* _MMIO(0xc1dc) */ 100 }; 101 102 static const struct xe_reg *pick_runtime_regs(struct xe_device *xe, unsigned int *count) 103 { 104 const struct xe_reg *regs; 105 106 if (GRAPHICS_VERx100(xe) >= 3000) { 107 *count = ARRAY_SIZE(ver_3000_runtime_regs); 108 regs = ver_3000_runtime_regs; 109 } else if (GRAPHICS_VERx100(xe) >= 2000) { 110 *count = ARRAY_SIZE(ver_2000_runtime_regs); 111 regs = ver_2000_runtime_regs; 112 } else if (GRAPHICS_VERx100(xe) >= 1270) { 113 *count = ARRAY_SIZE(ver_1270_runtime_regs); 114 regs = ver_1270_runtime_regs; 115 } else if (GRAPHICS_VERx100(xe) == 1260) { 116 *count = ARRAY_SIZE(pvc_runtime_regs); 117 regs = pvc_runtime_regs; 118 } else if (GRAPHICS_VERx100(xe) == 1255) { 119 *count = ARRAY_SIZE(ats_m_runtime_regs); 120 regs = ats_m_runtime_regs; 121 } else if (GRAPHICS_VERx100(xe) == 1200) { 122 *count = ARRAY_SIZE(tgl_runtime_regs); 123 regs = tgl_runtime_regs; 124 } else { 125 regs = ERR_PTR(-ENOPKG); 126 *count = 0; 127 } 128 129 return regs; 130 } 131 132 static int pf_alloc_runtime_info(struct xe_gt *gt) 133 { 134 struct xe_device *xe = gt_to_xe(gt); 135 const struct xe_reg *regs; 136 unsigned int size; 137 u32 *values; 138 139 xe_gt_assert(gt, IS_SRIOV_PF(xe)); 140 xe_gt_assert(gt, !gt->sriov.pf.service.runtime.size); 141 xe_gt_assert(gt, !gt->sriov.pf.service.runtime.regs); 142 xe_gt_assert(gt, !gt->sriov.pf.service.runtime.values); 143 144 regs = pick_runtime_regs(xe, &size); 145 if (IS_ERR(regs)) 146 return PTR_ERR(regs); 147 148 if (unlikely(!size)) 149 return 0; 150 151 values = drmm_kcalloc(&xe->drm, size, sizeof(u32), GFP_KERNEL); 152 if (!values) 153 return -ENOMEM; 154 155 gt->sriov.pf.service.runtime.size = size; 156 gt->sriov.pf.service.runtime.regs = regs; 157 gt->sriov.pf.service.runtime.values = values; 158 159 return 0; 160 } 161 162 static void read_many(struct xe_gt *gt, unsigned int count, 163 const struct xe_reg *regs, u32 *values) 164 { 165 while (count--) 166 *values++ = xe_mmio_read32(>->mmio, *regs++); 167 } 168 169 static void pf_prepare_runtime_info(struct xe_gt *gt) 170 { 171 const struct xe_reg *regs; 172 unsigned int size; 173 u32 *values; 174 175 if (!gt->sriov.pf.service.runtime.size) 176 return; 177 178 size = gt->sriov.pf.service.runtime.size; 179 regs = gt->sriov.pf.service.runtime.regs; 180 values = gt->sriov.pf.service.runtime.values; 181 182 read_many(gt, size, regs, values); 183 184 if (IS_ENABLED(CONFIG_DRM_XE_DEBUG_SRIOV)) { 185 struct drm_printer p = xe_gt_dbg_printer(gt); 186 187 xe_gt_sriov_pf_service_print_runtime(gt, &p); 188 } 189 } 190 191 /** 192 * xe_gt_sriov_pf_service_init - Early initialization of the GT SR-IOV PF services. 193 * @gt: the &xe_gt to initialize 194 * 195 * Performs early initialization of the GT SR-IOV PF services, including preparation 196 * of the runtime info that will be shared with VFs. 197 * 198 * This function can only be called on PF. 199 */ 200 int xe_gt_sriov_pf_service_init(struct xe_gt *gt) 201 { 202 int err; 203 204 err = pf_alloc_runtime_info(gt); 205 if (unlikely(err)) 206 goto failed; 207 208 return 0; 209 failed: 210 xe_gt_sriov_err(gt, "Failed to initialize service (%pe)\n", ERR_PTR(err)); 211 return err; 212 } 213 214 /** 215 * xe_gt_sriov_pf_service_update - Update PF SR-IOV services. 216 * @gt: the &xe_gt to update 217 * 218 * Updates runtime data shared with VFs. 219 * 220 * This function can be called more than once. 221 * This function can only be called on PF. 222 */ 223 void xe_gt_sriov_pf_service_update(struct xe_gt *gt) 224 { 225 pf_prepare_runtime_info(gt); 226 } 227 228 /* Return: length of the response message or a negative error code on failure. */ 229 static int pf_process_handshake_msg(struct xe_gt *gt, u32 origin, 230 const u32 *request, u32 len, u32 *response, u32 size) 231 { 232 u32 wanted_major, wanted_minor; 233 u32 major, minor; 234 u32 mbz; 235 int err; 236 237 if (unlikely(len != VF2PF_HANDSHAKE_REQUEST_MSG_LEN)) 238 return -EMSGSIZE; 239 240 mbz = FIELD_GET(VF2PF_HANDSHAKE_REQUEST_MSG_0_MBZ, request[0]); 241 if (unlikely(mbz)) 242 return -EPFNOSUPPORT; 243 244 wanted_major = FIELD_GET(VF2PF_HANDSHAKE_REQUEST_MSG_1_MAJOR, request[1]); 245 wanted_minor = FIELD_GET(VF2PF_HANDSHAKE_REQUEST_MSG_1_MINOR, request[1]); 246 247 err = xe_sriov_pf_service_handshake_vf(gt_to_xe(gt), origin, wanted_major, wanted_minor, 248 &major, &minor); 249 if (err < 0) 250 return err; 251 252 xe_gt_assert(gt, major || minor); 253 xe_gt_assert(gt, size >= VF2PF_HANDSHAKE_RESPONSE_MSG_LEN); 254 255 response[0] = FIELD_PREP(GUC_HXG_MSG_0_ORIGIN, GUC_HXG_ORIGIN_HOST) | 256 FIELD_PREP(GUC_HXG_MSG_0_TYPE, GUC_HXG_TYPE_RESPONSE_SUCCESS) | 257 FIELD_PREP(GUC_HXG_RESPONSE_MSG_0_DATA0, 0); 258 response[1] = FIELD_PREP(VF2PF_HANDSHAKE_RESPONSE_MSG_1_MAJOR, major) | 259 FIELD_PREP(VF2PF_HANDSHAKE_RESPONSE_MSG_1_MINOR, minor); 260 261 return VF2PF_HANDSHAKE_RESPONSE_MSG_LEN; 262 } 263 264 struct reg_data { 265 u32 offset; 266 u32 value; 267 } __packed; 268 static_assert(hxg_sizeof(struct reg_data) == 2); 269 270 /* Return: number of entries copied or negative error code on failure. */ 271 static int pf_service_runtime_query(struct xe_gt *gt, u32 start, u32 limit, 272 struct reg_data *data, u32 *remaining) 273 { 274 struct xe_gt_sriov_pf_service_runtime_regs *runtime; 275 unsigned int count, i; 276 u32 addr; 277 278 xe_gt_assert(gt, IS_SRIOV_PF(gt_to_xe(gt))); 279 280 runtime = >->sriov.pf.service.runtime; 281 282 if (start > runtime->size) 283 return -ERANGE; 284 285 count = min_t(u32, runtime->size - start, limit); 286 287 for (i = 0; i < count; ++i, ++data) { 288 addr = runtime->regs[start + i].addr; 289 data->offset = xe_mmio_adjusted_addr(>->mmio, addr); 290 data->value = runtime->values[start + i]; 291 } 292 293 *remaining = runtime->size - start - count; 294 return count; 295 } 296 297 /* Return: length of the response message or a negative error code on failure. */ 298 static int pf_process_runtime_query_msg(struct xe_gt *gt, u32 origin, 299 const u32 *msg, u32 msg_len, u32 *response, u32 resp_size) 300 { 301 const u32 chunk_size = hxg_sizeof(struct reg_data); 302 struct reg_data *reg_data_buf; 303 u32 limit, start, max_chunks; 304 u32 remaining = 0; 305 int ret; 306 307 /* this action is available from ABI 1.0 */ 308 if (!xe_sriov_pf_service_is_negotiated(gt_to_xe(gt), origin, 1, 0)) 309 return -EACCES; 310 311 if (unlikely(msg_len > VF2PF_QUERY_RUNTIME_REQUEST_MSG_LEN)) 312 return -EMSGSIZE; 313 if (unlikely(msg_len < VF2PF_QUERY_RUNTIME_REQUEST_MSG_LEN)) 314 return -EPROTO; 315 if (unlikely(resp_size < VF2PF_QUERY_RUNTIME_RESPONSE_MSG_MIN_LEN)) 316 return -EINVAL; 317 318 limit = FIELD_GET(VF2PF_QUERY_RUNTIME_REQUEST_MSG_0_LIMIT, msg[0]); 319 start = FIELD_GET(VF2PF_QUERY_RUNTIME_REQUEST_MSG_1_START, msg[1]); 320 321 resp_size = min_t(u32, resp_size, VF2PF_QUERY_RUNTIME_RESPONSE_MSG_MAX_LEN); 322 max_chunks = (resp_size - VF2PF_QUERY_RUNTIME_RESPONSE_MSG_MIN_LEN) / chunk_size; 323 limit = limit == VF2PF_QUERY_RUNTIME_NO_LIMIT ? max_chunks : min_t(u32, max_chunks, limit); 324 reg_data_buf = (void *)(response + VF2PF_QUERY_RUNTIME_RESPONSE_MSG_MIN_LEN); 325 326 ret = pf_service_runtime_query(gt, start, limit, reg_data_buf, &remaining); 327 if (ret < 0) 328 return ret; 329 330 response[0] = FIELD_PREP(GUC_HXG_MSG_0_ORIGIN, GUC_HXG_ORIGIN_HOST) | 331 FIELD_PREP(GUC_HXG_MSG_0_TYPE, GUC_HXG_TYPE_RESPONSE_SUCCESS) | 332 FIELD_PREP(VF2PF_QUERY_RUNTIME_RESPONSE_MSG_0_COUNT, ret); 333 response[1] = FIELD_PREP(VF2PF_QUERY_RUNTIME_RESPONSE_MSG_1_REMAINING, remaining); 334 335 return VF2PF_QUERY_RUNTIME_RESPONSE_MSG_MIN_LEN + ret * hxg_sizeof(struct reg_data); 336 } 337 338 /** 339 * xe_gt_sriov_pf_service_process_request - Service GT level SR-IOV request message from the VF. 340 * @gt: the &xe_gt that provides the service 341 * @origin: VF number that is requesting the service 342 * @msg: request message 343 * @msg_len: length of the request message (in dwords) 344 * @response: placeholder for the response message 345 * @resp_size: length of the response message buffer (in dwords) 346 * 347 * This function processes `Relay Message`_ request from the VF. 348 * 349 * Return: length of the response message or a negative error code on failure. 350 */ 351 int xe_gt_sriov_pf_service_process_request(struct xe_gt *gt, u32 origin, 352 const u32 *msg, u32 msg_len, 353 u32 *response, u32 resp_size) 354 { 355 u32 action, data __maybe_unused; 356 int ret; 357 358 xe_gt_assert(gt, msg_len >= GUC_HXG_MSG_MIN_LEN); 359 xe_gt_assert(gt, FIELD_GET(GUC_HXG_MSG_0_TYPE, msg[0]) == GUC_HXG_TYPE_REQUEST); 360 361 action = FIELD_GET(GUC_HXG_REQUEST_MSG_0_ACTION, msg[0]); 362 data = FIELD_GET(GUC_HXG_REQUEST_MSG_0_DATA0, msg[0]); 363 xe_gt_sriov_dbg_verbose(gt, "service action %#x:%u from VF%u\n", 364 action, data, origin); 365 366 switch (action) { 367 case GUC_RELAY_ACTION_VF2PF_HANDSHAKE: 368 ret = pf_process_handshake_msg(gt, origin, msg, msg_len, response, resp_size); 369 break; 370 case GUC_RELAY_ACTION_VF2PF_QUERY_RUNTIME: 371 ret = pf_process_runtime_query_msg(gt, origin, msg, msg_len, response, resp_size); 372 break; 373 default: 374 ret = -EOPNOTSUPP; 375 break; 376 } 377 378 return ret; 379 } 380 381 /** 382 * xe_gt_sriov_pf_service_print_runtime - Print PF runtime data shared with VFs. 383 * @gt: the &xe_gt 384 * @p: the &drm_printer 385 * 386 * This function is for PF use only. 387 */ 388 int xe_gt_sriov_pf_service_print_runtime(struct xe_gt *gt, struct drm_printer *p) 389 { 390 const struct xe_reg *regs; 391 unsigned int size; 392 u32 *values; 393 394 xe_gt_assert(gt, IS_SRIOV_PF(gt_to_xe(gt))); 395 396 size = gt->sriov.pf.service.runtime.size; 397 regs = gt->sriov.pf.service.runtime.regs; 398 values = gt->sriov.pf.service.runtime.values; 399 400 for (; size--; regs++, values++) { 401 drm_printf(p, "reg[%#x] = %#x\n", 402 xe_mmio_adjusted_addr(>->mmio, regs->addr), *values); 403 } 404 405 return 0; 406 } 407