1 // SPDX-License-Identifier: MIT 2 /* 3 * Copyright © 2016-2019 Intel Corporation 4 */ 5 6 #include <linux/bitfield.h> 7 #include <linux/firmware.h> 8 #include <drm/drm_print.h> 9 10 #include "intel_uc_fw.h" 11 #include "intel_uc_fw_abi.h" 12 #include "i915_drv.h" 13 14 #ifdef CONFIG_DRM_I915_DEBUG_GUC 15 static inline struct intel_gt *__uc_fw_to_gt(struct intel_uc_fw *uc_fw) 16 { 17 GEM_BUG_ON(uc_fw->status == INTEL_UC_FIRMWARE_UNINITIALIZED); 18 if (uc_fw->type == INTEL_UC_FW_TYPE_GUC) 19 return container_of(uc_fw, struct intel_gt, uc.guc.fw); 20 21 GEM_BUG_ON(uc_fw->type != INTEL_UC_FW_TYPE_HUC); 22 return container_of(uc_fw, struct intel_gt, uc.huc.fw); 23 } 24 25 void intel_uc_fw_change_status(struct intel_uc_fw *uc_fw, 26 enum intel_uc_fw_status status) 27 { 28 uc_fw->__status = status; 29 DRM_DEV_DEBUG_DRIVER(__uc_fw_to_gt(uc_fw)->i915->drm.dev, 30 "%s firmware -> %s\n", 31 intel_uc_fw_type_repr(uc_fw->type), 32 status == INTEL_UC_FIRMWARE_SELECTED ? 33 uc_fw->path : intel_uc_fw_status_repr(status)); 34 } 35 #endif 36 37 /* 38 * List of required GuC and HuC binaries per-platform. 39 * Must be ordered based on platform + revid, from newer to older. 40 */ 41 #define INTEL_UC_FIRMWARE_DEFS(fw_def, guc_def, huc_def) \ 42 fw_def(ICELAKE, 0, guc_def(icl, 33, 0, 0), huc_def(icl, 8, 4, 3238)) \ 43 fw_def(COFFEELAKE, 0, guc_def(kbl, 33, 0, 0), huc_def(kbl, 02, 00, 1810)) \ 44 fw_def(GEMINILAKE, 0, guc_def(glk, 33, 0, 0), huc_def(glk, 03, 01, 2893)) \ 45 fw_def(KABYLAKE, 0, guc_def(kbl, 33, 0, 0), huc_def(kbl, 02, 00, 1810)) \ 46 fw_def(BROXTON, 0, guc_def(bxt, 33, 0, 0), huc_def(bxt, 01, 8, 2893)) \ 47 fw_def(SKYLAKE, 0, guc_def(skl, 33, 0, 0), huc_def(skl, 01, 07, 1398)) 48 49 #define __MAKE_UC_FW_PATH(prefix_, name_, separator_, major_, minor_, patch_) \ 50 "i915/" \ 51 __stringify(prefix_) name_ \ 52 __stringify(major_) separator_ \ 53 __stringify(minor_) separator_ \ 54 __stringify(patch_) ".bin" 55 56 #define MAKE_GUC_FW_PATH(prefix_, major_, minor_, patch_) \ 57 __MAKE_UC_FW_PATH(prefix_, "_guc_", ".", major_, minor_, patch_) 58 59 #define MAKE_HUC_FW_PATH(prefix_, major_, minor_, bld_num_) \ 60 __MAKE_UC_FW_PATH(prefix_, "_huc_ver", "_", major_, minor_, bld_num_) 61 62 /* All blobs need to be declared via MODULE_FIRMWARE() */ 63 #define INTEL_UC_MODULE_FW(platform_, revid_, guc_, huc_) \ 64 MODULE_FIRMWARE(guc_); \ 65 MODULE_FIRMWARE(huc_); 66 67 INTEL_UC_FIRMWARE_DEFS(INTEL_UC_MODULE_FW, MAKE_GUC_FW_PATH, MAKE_HUC_FW_PATH) 68 69 /* The below structs and macros are used to iterate across the list of blobs */ 70 struct __packed uc_fw_blob { 71 u8 major; 72 u8 minor; 73 const char *path; 74 }; 75 76 #define UC_FW_BLOB(major_, minor_, path_) \ 77 { .major = major_, .minor = minor_, .path = path_ } 78 79 #define GUC_FW_BLOB(prefix_, major_, minor_, patch_) \ 80 UC_FW_BLOB(major_, minor_, \ 81 MAKE_GUC_FW_PATH(prefix_, major_, minor_, patch_)) 82 83 #define HUC_FW_BLOB(prefix_, major_, minor_, bld_num_) \ 84 UC_FW_BLOB(major_, minor_, \ 85 MAKE_HUC_FW_PATH(prefix_, major_, minor_, bld_num_)) 86 87 struct __packed uc_fw_platform_requirement { 88 enum intel_platform p; 89 u8 rev; /* first platform rev using this FW */ 90 const struct uc_fw_blob blobs[INTEL_UC_FW_NUM_TYPES]; 91 }; 92 93 #define MAKE_FW_LIST(platform_, revid_, guc_, huc_) \ 94 { \ 95 .p = INTEL_##platform_, \ 96 .rev = revid_, \ 97 .blobs[INTEL_UC_FW_TYPE_GUC] = guc_, \ 98 .blobs[INTEL_UC_FW_TYPE_HUC] = huc_, \ 99 }, 100 101 static void 102 __uc_fw_auto_select(struct intel_uc_fw *uc_fw, enum intel_platform p, u8 rev) 103 { 104 static const struct uc_fw_platform_requirement fw_blobs[] = { 105 INTEL_UC_FIRMWARE_DEFS(MAKE_FW_LIST, GUC_FW_BLOB, HUC_FW_BLOB) 106 }; 107 int i; 108 109 for (i = 0; i < ARRAY_SIZE(fw_blobs) && p <= fw_blobs[i].p; i++) { 110 if (p == fw_blobs[i].p && rev >= fw_blobs[i].rev) { 111 const struct uc_fw_blob *blob = 112 &fw_blobs[i].blobs[uc_fw->type]; 113 uc_fw->path = blob->path; 114 uc_fw->major_ver_wanted = blob->major; 115 uc_fw->minor_ver_wanted = blob->minor; 116 break; 117 } 118 } 119 120 /* make sure the list is ordered as expected */ 121 if (IS_ENABLED(CONFIG_DRM_I915_SELFTEST)) { 122 for (i = 1; i < ARRAY_SIZE(fw_blobs); i++) { 123 if (fw_blobs[i].p < fw_blobs[i - 1].p) 124 continue; 125 126 if (fw_blobs[i].p == fw_blobs[i - 1].p && 127 fw_blobs[i].rev < fw_blobs[i - 1].rev) 128 continue; 129 130 pr_err("invalid FW blob order: %s r%u comes before %s r%u\n", 131 intel_platform_name(fw_blobs[i - 1].p), 132 fw_blobs[i - 1].rev, 133 intel_platform_name(fw_blobs[i].p), 134 fw_blobs[i].rev); 135 136 uc_fw->path = NULL; 137 } 138 } 139 140 /* We don't want to enable GuC/HuC on pre-Gen11 by default */ 141 if (i915_modparams.enable_guc == -1 && p < INTEL_ICELAKE) 142 uc_fw->path = NULL; 143 } 144 145 static const char *__override_guc_firmware_path(void) 146 { 147 if (i915_modparams.enable_guc & (ENABLE_GUC_SUBMISSION | 148 ENABLE_GUC_LOAD_HUC)) 149 return i915_modparams.guc_firmware_path; 150 return ""; 151 } 152 153 static const char *__override_huc_firmware_path(void) 154 { 155 if (i915_modparams.enable_guc & ENABLE_GUC_LOAD_HUC) 156 return i915_modparams.huc_firmware_path; 157 return ""; 158 } 159 160 static void __uc_fw_user_override(struct intel_uc_fw *uc_fw) 161 { 162 const char *path = NULL; 163 164 switch (uc_fw->type) { 165 case INTEL_UC_FW_TYPE_GUC: 166 path = __override_guc_firmware_path(); 167 break; 168 case INTEL_UC_FW_TYPE_HUC: 169 path = __override_huc_firmware_path(); 170 break; 171 } 172 173 if (unlikely(path)) { 174 uc_fw->path = path; 175 uc_fw->user_overridden = true; 176 } 177 } 178 179 /** 180 * intel_uc_fw_init_early - initialize the uC object and select the firmware 181 * @uc_fw: uC firmware 182 * @type: type of uC 183 * @supported: is uC support possible 184 * @platform: platform identifier 185 * @rev: hardware revision 186 * 187 * Initialize the state of our uC object and relevant tracking and select the 188 * firmware to fetch and load. 189 */ 190 void intel_uc_fw_init_early(struct intel_uc_fw *uc_fw, 191 enum intel_uc_fw_type type, bool supported, 192 enum intel_platform platform, u8 rev) 193 { 194 /* 195 * we use FIRMWARE_UNINITIALIZED to detect checks against uc_fw->status 196 * before we're looked at the HW caps to see if we have uc support 197 */ 198 BUILD_BUG_ON(INTEL_UC_FIRMWARE_UNINITIALIZED); 199 GEM_BUG_ON(uc_fw->status); 200 GEM_BUG_ON(uc_fw->path); 201 202 uc_fw->type = type; 203 204 if (supported) { 205 __uc_fw_auto_select(uc_fw, platform, rev); 206 __uc_fw_user_override(uc_fw); 207 } 208 209 intel_uc_fw_change_status(uc_fw, uc_fw->path ? *uc_fw->path ? 210 INTEL_UC_FIRMWARE_SELECTED : 211 INTEL_UC_FIRMWARE_DISABLED : 212 INTEL_UC_FIRMWARE_NOT_SUPPORTED); 213 } 214 215 static void __force_fw_fetch_failures(struct intel_uc_fw *uc_fw, 216 struct drm_i915_private *i915, 217 int e) 218 { 219 bool user = e == -EINVAL; 220 221 if (i915_inject_load_error(i915, e)) { 222 /* non-existing blob */ 223 uc_fw->path = "<invalid>"; 224 uc_fw->user_overridden = user; 225 } else if (i915_inject_load_error(i915, e)) { 226 /* require next major version */ 227 uc_fw->major_ver_wanted += 1; 228 uc_fw->minor_ver_wanted = 0; 229 uc_fw->user_overridden = user; 230 } else if (i915_inject_load_error(i915, e)) { 231 /* require next minor version */ 232 uc_fw->minor_ver_wanted += 1; 233 uc_fw->user_overridden = user; 234 } else if (uc_fw->major_ver_wanted && i915_inject_load_error(i915, e)) { 235 /* require prev major version */ 236 uc_fw->major_ver_wanted -= 1; 237 uc_fw->minor_ver_wanted = 0; 238 uc_fw->user_overridden = user; 239 } else if (uc_fw->minor_ver_wanted && i915_inject_load_error(i915, e)) { 240 /* require prev minor version - hey, this should work! */ 241 uc_fw->minor_ver_wanted -= 1; 242 uc_fw->user_overridden = user; 243 } else if (user && i915_inject_load_error(i915, e)) { 244 /* officially unsupported platform */ 245 uc_fw->major_ver_wanted = 0; 246 uc_fw->minor_ver_wanted = 0; 247 uc_fw->user_overridden = true; 248 } 249 } 250 251 /** 252 * intel_uc_fw_fetch - fetch uC firmware 253 * @uc_fw: uC firmware 254 * @i915: device private 255 * 256 * Fetch uC firmware into GEM obj. 257 * 258 * Return: 0 on success, a negative errno code on failure. 259 */ 260 int intel_uc_fw_fetch(struct intel_uc_fw *uc_fw, struct drm_i915_private *i915) 261 { 262 struct device *dev = i915->drm.dev; 263 struct drm_i915_gem_object *obj; 264 const struct firmware *fw = NULL; 265 struct uc_css_header *css; 266 size_t size; 267 int err; 268 269 GEM_BUG_ON(!i915->wopcm.size); 270 GEM_BUG_ON(!intel_uc_fw_is_enabled(uc_fw)); 271 272 err = i915_inject_load_error(i915, -ENXIO); 273 if (err) 274 return err; 275 276 __force_fw_fetch_failures(uc_fw, i915, -EINVAL); 277 __force_fw_fetch_failures(uc_fw, i915, -ESTALE); 278 279 err = request_firmware(&fw, uc_fw->path, dev); 280 if (err) 281 goto fail; 282 283 /* Check the size of the blob before examining buffer contents */ 284 if (unlikely(fw->size < sizeof(struct uc_css_header))) { 285 dev_warn(dev, "%s firmware %s: invalid size: %zu < %zu\n", 286 intel_uc_fw_type_repr(uc_fw->type), uc_fw->path, 287 fw->size, sizeof(struct uc_css_header)); 288 err = -ENODATA; 289 goto fail; 290 } 291 292 css = (struct uc_css_header *)fw->data; 293 294 /* Check integrity of size values inside CSS header */ 295 size = (css->header_size_dw - css->key_size_dw - css->modulus_size_dw - 296 css->exponent_size_dw) * sizeof(u32); 297 if (unlikely(size != sizeof(struct uc_css_header))) { 298 dev_warn(dev, 299 "%s firmware %s: unexpected header size: %zu != %zu\n", 300 intel_uc_fw_type_repr(uc_fw->type), uc_fw->path, 301 fw->size, sizeof(struct uc_css_header)); 302 err = -EPROTO; 303 goto fail; 304 } 305 306 /* uCode size must calculated from other sizes */ 307 uc_fw->ucode_size = (css->size_dw - css->header_size_dw) * sizeof(u32); 308 309 /* now RSA */ 310 if (unlikely(css->key_size_dw != UOS_RSA_SCRATCH_COUNT)) { 311 dev_warn(dev, "%s firmware %s: unexpected key size: %u != %u\n", 312 intel_uc_fw_type_repr(uc_fw->type), uc_fw->path, 313 css->key_size_dw, UOS_RSA_SCRATCH_COUNT); 314 err = -EPROTO; 315 goto fail; 316 } 317 uc_fw->rsa_size = css->key_size_dw * sizeof(u32); 318 319 /* At least, it should have header, uCode and RSA. Size of all three. */ 320 size = sizeof(struct uc_css_header) + uc_fw->ucode_size + uc_fw->rsa_size; 321 if (unlikely(fw->size < size)) { 322 dev_warn(dev, "%s firmware %s: invalid size: %zu < %zu\n", 323 intel_uc_fw_type_repr(uc_fw->type), uc_fw->path, 324 fw->size, size); 325 err = -ENOEXEC; 326 goto fail; 327 } 328 329 /* Sanity check whether this fw is not larger than whole WOPCM memory */ 330 size = __intel_uc_fw_get_upload_size(uc_fw); 331 if (unlikely(size >= i915->wopcm.size)) { 332 dev_warn(dev, "%s firmware %s: invalid size: %zu > %zu\n", 333 intel_uc_fw_type_repr(uc_fw->type), uc_fw->path, 334 size, (size_t)i915->wopcm.size); 335 err = -E2BIG; 336 goto fail; 337 } 338 339 /* Get version numbers from the CSS header */ 340 switch (uc_fw->type) { 341 case INTEL_UC_FW_TYPE_GUC: 342 uc_fw->major_ver_found = FIELD_GET(CSS_SW_VERSION_GUC_MAJOR, 343 css->sw_version); 344 uc_fw->minor_ver_found = FIELD_GET(CSS_SW_VERSION_GUC_MINOR, 345 css->sw_version); 346 break; 347 348 case INTEL_UC_FW_TYPE_HUC: 349 uc_fw->major_ver_found = FIELD_GET(CSS_SW_VERSION_HUC_MAJOR, 350 css->sw_version); 351 uc_fw->minor_ver_found = FIELD_GET(CSS_SW_VERSION_HUC_MINOR, 352 css->sw_version); 353 break; 354 355 default: 356 MISSING_CASE(uc_fw->type); 357 break; 358 } 359 360 if (uc_fw->major_ver_found != uc_fw->major_ver_wanted || 361 uc_fw->minor_ver_found < uc_fw->minor_ver_wanted) { 362 dev_notice(dev, "%s firmware %s: unexpected version: %u.%u != %u.%u\n", 363 intel_uc_fw_type_repr(uc_fw->type), uc_fw->path, 364 uc_fw->major_ver_found, uc_fw->minor_ver_found, 365 uc_fw->major_ver_wanted, uc_fw->minor_ver_wanted); 366 if (!intel_uc_fw_is_overridden(uc_fw)) { 367 err = -ENOEXEC; 368 goto fail; 369 } 370 } 371 372 obj = i915_gem_object_create_shmem_from_data(i915, fw->data, fw->size); 373 if (IS_ERR(obj)) { 374 err = PTR_ERR(obj); 375 goto fail; 376 } 377 378 uc_fw->obj = obj; 379 uc_fw->size = fw->size; 380 intel_uc_fw_change_status(uc_fw, INTEL_UC_FIRMWARE_AVAILABLE); 381 382 release_firmware(fw); 383 return 0; 384 385 fail: 386 intel_uc_fw_change_status(uc_fw, err == -ENOENT ? 387 INTEL_UC_FIRMWARE_MISSING : 388 INTEL_UC_FIRMWARE_ERROR); 389 390 dev_notice(dev, "%s firmware %s: fetch failed with error %d\n", 391 intel_uc_fw_type_repr(uc_fw->type), uc_fw->path, err); 392 dev_info(dev, "%s firmware(s) can be downloaded from %s\n", 393 intel_uc_fw_type_repr(uc_fw->type), INTEL_UC_FIRMWARE_URL); 394 395 release_firmware(fw); /* OK even if fw is NULL */ 396 return err; 397 } 398 399 static u32 uc_fw_ggtt_offset(struct intel_uc_fw *uc_fw, struct i915_ggtt *ggtt) 400 { 401 struct drm_mm_node *node = &ggtt->uc_fw; 402 403 GEM_BUG_ON(!node->allocated); 404 GEM_BUG_ON(upper_32_bits(node->start)); 405 GEM_BUG_ON(upper_32_bits(node->start + node->size - 1)); 406 407 return lower_32_bits(node->start); 408 } 409 410 static void intel_uc_fw_ggtt_bind(struct intel_uc_fw *uc_fw, 411 struct intel_gt *gt) 412 { 413 struct drm_i915_gem_object *obj = uc_fw->obj; 414 struct i915_ggtt *ggtt = gt->ggtt; 415 struct i915_vma dummy = { 416 .node.start = uc_fw_ggtt_offset(uc_fw, ggtt), 417 .node.size = obj->base.size, 418 .pages = obj->mm.pages, 419 .vm = &ggtt->vm, 420 }; 421 422 GEM_BUG_ON(!i915_gem_object_has_pinned_pages(obj)); 423 GEM_BUG_ON(dummy.node.size > ggtt->uc_fw.size); 424 425 /* uc_fw->obj cache domains were not controlled across suspend */ 426 drm_clflush_sg(dummy.pages); 427 428 ggtt->vm.insert_entries(&ggtt->vm, &dummy, I915_CACHE_NONE, 0); 429 } 430 431 static void intel_uc_fw_ggtt_unbind(struct intel_uc_fw *uc_fw, 432 struct intel_gt *gt) 433 { 434 struct drm_i915_gem_object *obj = uc_fw->obj; 435 struct i915_ggtt *ggtt = gt->ggtt; 436 u64 start = uc_fw_ggtt_offset(uc_fw, ggtt); 437 438 ggtt->vm.clear_range(&ggtt->vm, start, obj->base.size); 439 } 440 441 static int uc_fw_xfer(struct intel_uc_fw *uc_fw, struct intel_gt *gt, 442 u32 wopcm_offset, u32 dma_flags) 443 { 444 struct intel_uncore *uncore = gt->uncore; 445 u64 offset; 446 int ret; 447 448 ret = i915_inject_load_error(gt->i915, -ETIMEDOUT); 449 if (ret) 450 return ret; 451 452 intel_uncore_forcewake_get(uncore, FORCEWAKE_ALL); 453 454 /* Set the source address for the uCode */ 455 offset = uc_fw_ggtt_offset(uc_fw, gt->ggtt); 456 GEM_BUG_ON(upper_32_bits(offset) & 0xFFFF0000); 457 intel_uncore_write_fw(uncore, DMA_ADDR_0_LOW, lower_32_bits(offset)); 458 intel_uncore_write_fw(uncore, DMA_ADDR_0_HIGH, upper_32_bits(offset)); 459 460 /* Set the DMA destination */ 461 intel_uncore_write_fw(uncore, DMA_ADDR_1_LOW, wopcm_offset); 462 intel_uncore_write_fw(uncore, DMA_ADDR_1_HIGH, DMA_ADDRESS_SPACE_WOPCM); 463 464 /* 465 * Set the transfer size. The header plus uCode will be copied to WOPCM 466 * via DMA, excluding any other components 467 */ 468 intel_uncore_write_fw(uncore, DMA_COPY_SIZE, 469 sizeof(struct uc_css_header) + uc_fw->ucode_size); 470 471 /* Start the DMA */ 472 intel_uncore_write_fw(uncore, DMA_CTRL, 473 _MASKED_BIT_ENABLE(dma_flags | START_DMA)); 474 475 /* Wait for DMA to finish */ 476 ret = intel_wait_for_register_fw(uncore, DMA_CTRL, START_DMA, 0, 100); 477 if (ret) 478 dev_err(gt->i915->drm.dev, "DMA for %s fw failed, DMA_CTRL=%u\n", 479 intel_uc_fw_type_repr(uc_fw->type), 480 intel_uncore_read_fw(uncore, DMA_CTRL)); 481 482 /* Disable the bits once DMA is over */ 483 intel_uncore_write_fw(uncore, DMA_CTRL, _MASKED_BIT_DISABLE(dma_flags)); 484 485 intel_uncore_forcewake_put(uncore, FORCEWAKE_ALL); 486 487 return ret; 488 } 489 490 /** 491 * intel_uc_fw_upload - load uC firmware using custom loader 492 * @uc_fw: uC firmware 493 * @gt: the intel_gt structure 494 * @wopcm_offset: destination offset in wopcm 495 * @dma_flags: flags for flags for dma ctrl 496 * 497 * Loads uC firmware and updates internal flags. 498 * 499 * Return: 0 on success, non-zero on failure. 500 */ 501 int intel_uc_fw_upload(struct intel_uc_fw *uc_fw, struct intel_gt *gt, 502 u32 wopcm_offset, u32 dma_flags) 503 { 504 int err; 505 506 /* make sure the status was cleared the last time we reset the uc */ 507 GEM_BUG_ON(intel_uc_fw_is_loaded(uc_fw)); 508 509 err = i915_inject_load_error(gt->i915, -ENOEXEC); 510 if (err) 511 return err; 512 513 if (!intel_uc_fw_is_available(uc_fw)) 514 return -ENOEXEC; 515 516 /* Call custom loader */ 517 intel_uc_fw_ggtt_bind(uc_fw, gt); 518 err = uc_fw_xfer(uc_fw, gt, wopcm_offset, dma_flags); 519 intel_uc_fw_ggtt_unbind(uc_fw, gt); 520 if (err) 521 goto fail; 522 523 intel_uc_fw_change_status(uc_fw, INTEL_UC_FIRMWARE_TRANSFERRED); 524 return 0; 525 526 fail: 527 i915_probe_error(gt->i915, "Failed to load %s firmware %s (%d)\n", 528 intel_uc_fw_type_repr(uc_fw->type), uc_fw->path, 529 err); 530 intel_uc_fw_change_status(uc_fw, INTEL_UC_FIRMWARE_FAIL); 531 return err; 532 } 533 534 int intel_uc_fw_init(struct intel_uc_fw *uc_fw) 535 { 536 int err; 537 538 /* this should happen before the load! */ 539 GEM_BUG_ON(intel_uc_fw_is_loaded(uc_fw)); 540 541 if (!intel_uc_fw_is_available(uc_fw)) 542 return -ENOEXEC; 543 544 err = i915_gem_object_pin_pages(uc_fw->obj); 545 if (err) { 546 DRM_DEBUG_DRIVER("%s fw pin-pages err=%d\n", 547 intel_uc_fw_type_repr(uc_fw->type), err); 548 intel_uc_fw_change_status(uc_fw, INTEL_UC_FIRMWARE_FAIL); 549 } 550 551 return err; 552 } 553 554 void intel_uc_fw_fini(struct intel_uc_fw *uc_fw) 555 { 556 if (!intel_uc_fw_is_available(uc_fw)) 557 return; 558 559 i915_gem_object_unpin_pages(uc_fw->obj); 560 } 561 562 /** 563 * intel_uc_fw_cleanup_fetch - cleanup uC firmware 564 * @uc_fw: uC firmware 565 * 566 * Cleans up uC firmware by releasing the firmware GEM obj. 567 */ 568 void intel_uc_fw_cleanup_fetch(struct intel_uc_fw *uc_fw) 569 { 570 if (!intel_uc_fw_is_available(uc_fw)) 571 return; 572 573 i915_gem_object_put(fetch_and_zero(&uc_fw->obj)); 574 575 intel_uc_fw_change_status(uc_fw, INTEL_UC_FIRMWARE_SELECTED); 576 } 577 578 /** 579 * intel_uc_fw_copy_rsa - copy fw RSA to buffer 580 * 581 * @uc_fw: uC firmware 582 * @dst: dst buffer 583 * @max_len: max number of bytes to copy 584 * 585 * Return: number of copied bytes. 586 */ 587 size_t intel_uc_fw_copy_rsa(struct intel_uc_fw *uc_fw, void *dst, u32 max_len) 588 { 589 struct sg_table *pages = uc_fw->obj->mm.pages; 590 u32 size = min_t(u32, uc_fw->rsa_size, max_len); 591 u32 offset = sizeof(struct uc_css_header) + uc_fw->ucode_size; 592 593 GEM_BUG_ON(!intel_uc_fw_is_available(uc_fw)); 594 595 return sg_pcopy_to_buffer(pages->sgl, pages->nents, dst, size, offset); 596 } 597 598 /** 599 * intel_uc_fw_dump - dump information about uC firmware 600 * @uc_fw: uC firmware 601 * @p: the &drm_printer 602 * 603 * Pretty printer for uC firmware. 604 */ 605 void intel_uc_fw_dump(const struct intel_uc_fw *uc_fw, struct drm_printer *p) 606 { 607 drm_printf(p, "%s firmware: %s\n", 608 intel_uc_fw_type_repr(uc_fw->type), uc_fw->path); 609 drm_printf(p, "\tstatus: %s\n", 610 intel_uc_fw_status_repr(uc_fw->status)); 611 drm_printf(p, "\tversion: wanted %u.%u, found %u.%u\n", 612 uc_fw->major_ver_wanted, uc_fw->minor_ver_wanted, 613 uc_fw->major_ver_found, uc_fw->minor_ver_found); 614 drm_printf(p, "\tuCode: %u bytes\n", uc_fw->ucode_size); 615 drm_printf(p, "\tRSA: %u bytes\n", uc_fw->rsa_size); 616 } 617