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