intel_uc_fw.c 17.7 KB
Newer Older
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 13
#include "i915_drv.h"

14 15
static inline struct intel_gt *
____uc_fw_to_gt(struct intel_uc_fw *uc_fw, enum intel_uc_fw_type type)
16
{
17
	if (type == INTEL_UC_FW_TYPE_GUC)
18 19
		return container_of(uc_fw, struct intel_gt, uc.guc.fw);

20
	GEM_BUG_ON(type != INTEL_UC_FW_TYPE_HUC);
21 22 23
	return container_of(uc_fw, struct intel_gt, uc.huc.fw);
}

24 25 26 27 28 29
static inline struct intel_gt *__uc_fw_to_gt(struct intel_uc_fw *uc_fw)
{
	GEM_BUG_ON(uc_fw->status == INTEL_UC_FIRMWARE_UNINITIALIZED);
	return ____uc_fw_to_gt(uc_fw, uc_fw->type);
}

30
#ifdef CONFIG_DRM_I915_DEBUG_GUC
31 32 33 34
void intel_uc_fw_change_status(struct intel_uc_fw *uc_fw,
			       enum intel_uc_fw_status status)
{
	uc_fw->__status =  status;
35 36 37 38 39
	drm_dbg(&__uc_fw_to_gt(uc_fw)->i915->drm,
		"%s firmware -> %s\n",
		intel_uc_fw_type_repr(uc_fw->type),
		status == INTEL_UC_FIRMWARE_SELECTED ?
		uc_fw->path : intel_uc_fw_status_repr(status));
40 41 42
}
#endif

43 44 45
/*
 * List of required GuC and HuC binaries per-platform.
 * Must be ordered based on platform + revid, from newer to older.
46 47 48 49
 *
 * TGL 35.2 is interface-compatible with 33.0 for previous Gens. The deltas
 * between 33.0 and 35.2 are only related to new additions to support new Gen12
 * features.
50 51
 */
#define INTEL_UC_FIRMWARE_DEFS(fw_def, guc_def, huc_def) \
52
	fw_def(TIGERLAKE,   0, guc_def(tgl, 35, 2, 0), huc_def(tgl,  7, 0, 12)) \
53 54 55 56 57 58 59 60
	fw_def(ELKHARTLAKE, 0, guc_def(ehl, 33, 0, 4), huc_def(ehl,  9, 0, 0)) \
	fw_def(ICELAKE,     0, guc_def(icl, 33, 0, 0), huc_def(icl,  9, 0, 0)) \
	fw_def(COFFEELAKE,  5, guc_def(cml, 33, 0, 0), huc_def(cml,  4, 0, 0)) \
	fw_def(COFFEELAKE,  0, guc_def(kbl, 33, 0, 0), huc_def(kbl,  4, 0, 0)) \
	fw_def(GEMINILAKE,  0, guc_def(glk, 33, 0, 0), huc_def(glk,  4, 0, 0)) \
	fw_def(KABYLAKE,    0, guc_def(kbl, 33, 0, 0), huc_def(kbl,  4, 0, 0)) \
	fw_def(BROXTON,     0, guc_def(bxt, 33, 0, 0), huc_def(bxt,  2, 0, 0)) \
	fw_def(SKYLAKE,     0, guc_def(skl, 33, 0, 0), huc_def(skl,  2, 0, 0))
61

62
#define __MAKE_UC_FW_PATH(prefix_, name_, major_, minor_, patch_) \
63 64
	"i915/" \
	__stringify(prefix_) name_ \
65 66
	__stringify(major_) "." \
	__stringify(minor_) "." \
67 68 69
	__stringify(patch_) ".bin"

#define MAKE_GUC_FW_PATH(prefix_, major_, minor_, patch_) \
70
	__MAKE_UC_FW_PATH(prefix_, "_guc_", major_, minor_, patch_)
71 72

#define MAKE_HUC_FW_PATH(prefix_, major_, minor_, bld_num_) \
73
	__MAKE_UC_FW_PATH(prefix_, "_huc_", major_, minor_, bld_num_)
74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151

/* All blobs need to be declared via MODULE_FIRMWARE() */
#define INTEL_UC_MODULE_FW(platform_, revid_, guc_, huc_) \
	MODULE_FIRMWARE(guc_); \
	MODULE_FIRMWARE(huc_);

INTEL_UC_FIRMWARE_DEFS(INTEL_UC_MODULE_FW, MAKE_GUC_FW_PATH, MAKE_HUC_FW_PATH)

/* The below structs and macros are used to iterate across the list of blobs */
struct __packed uc_fw_blob {
	u8 major;
	u8 minor;
	const char *path;
};

#define UC_FW_BLOB(major_, minor_, path_) \
	{ .major = major_, .minor = minor_, .path = path_ }

#define GUC_FW_BLOB(prefix_, major_, minor_, patch_) \
	UC_FW_BLOB(major_, minor_, \
		   MAKE_GUC_FW_PATH(prefix_, major_, minor_, patch_))

#define HUC_FW_BLOB(prefix_, major_, minor_, bld_num_) \
	UC_FW_BLOB(major_, minor_, \
		   MAKE_HUC_FW_PATH(prefix_, major_, minor_, bld_num_))

struct __packed uc_fw_platform_requirement {
	enum intel_platform p;
	u8 rev; /* first platform rev using this FW */
	const struct uc_fw_blob blobs[INTEL_UC_FW_NUM_TYPES];
};

#define MAKE_FW_LIST(platform_, revid_, guc_, huc_) \
{ \
	.p = INTEL_##platform_, \
	.rev = revid_, \
	.blobs[INTEL_UC_FW_TYPE_GUC] = guc_, \
	.blobs[INTEL_UC_FW_TYPE_HUC] = huc_, \
},

static void
__uc_fw_auto_select(struct intel_uc_fw *uc_fw, enum intel_platform p, u8 rev)
{
	static const struct uc_fw_platform_requirement fw_blobs[] = {
		INTEL_UC_FIRMWARE_DEFS(MAKE_FW_LIST, GUC_FW_BLOB, HUC_FW_BLOB)
	};
	int i;

	for (i = 0; i < ARRAY_SIZE(fw_blobs) && p <= fw_blobs[i].p; i++) {
		if (p == fw_blobs[i].p && rev >= fw_blobs[i].rev) {
			const struct uc_fw_blob *blob =
					&fw_blobs[i].blobs[uc_fw->type];
			uc_fw->path = blob->path;
			uc_fw->major_ver_wanted = blob->major;
			uc_fw->minor_ver_wanted = blob->minor;
			break;
		}
	}

	/* make sure the list is ordered as expected */
	if (IS_ENABLED(CONFIG_DRM_I915_SELFTEST)) {
		for (i = 1; i < ARRAY_SIZE(fw_blobs); i++) {
			if (fw_blobs[i].p < fw_blobs[i - 1].p)
				continue;

			if (fw_blobs[i].p == fw_blobs[i - 1].p &&
			    fw_blobs[i].rev < fw_blobs[i - 1].rev)
				continue;

			pr_err("invalid FW blob order: %s r%u comes before %s r%u\n",
			       intel_platform_name(fw_blobs[i - 1].p),
			       fw_blobs[i - 1].rev,
			       intel_platform_name(fw_blobs[i].p),
			       fw_blobs[i].rev);

			uc_fw->path = NULL;
		}
	}
152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170

	/* We don't want to enable GuC/HuC on pre-Gen11 by default */
	if (i915_modparams.enable_guc == -1 && p < INTEL_ICELAKE)
		uc_fw->path = NULL;
}

static const char *__override_guc_firmware_path(void)
{
	if (i915_modparams.enable_guc & (ENABLE_GUC_SUBMISSION |
					 ENABLE_GUC_LOAD_HUC))
		return i915_modparams.guc_firmware_path;
	return "";
}

static const char *__override_huc_firmware_path(void)
{
	if (i915_modparams.enable_guc & ENABLE_GUC_LOAD_HUC)
		return i915_modparams.huc_firmware_path;
	return "";
171 172
}

173
static void __uc_fw_user_override(struct intel_uc_fw *uc_fw)
174
{
175 176
	const char *path = NULL;

177 178
	switch (uc_fw->type) {
	case INTEL_UC_FW_TYPE_GUC:
179
		path = __override_guc_firmware_path();
180 181
		break;
	case INTEL_UC_FW_TYPE_HUC:
182
		path = __override_huc_firmware_path();
183 184 185
		break;
	}

186 187 188 189
	if (unlikely(path)) {
		uc_fw->path = path;
		uc_fw->user_overridden = true;
	}
190 191 192 193 194 195 196 197 198 199 200
}

/**
 * intel_uc_fw_init_early - initialize the uC object and select the firmware
 * @uc_fw: uC firmware
 * @type: type of uC
 *
 * Initialize the state of our uC object and relevant tracking and select the
 * firmware to fetch and load.
 */
void intel_uc_fw_init_early(struct intel_uc_fw *uc_fw,
201
			    enum intel_uc_fw_type type)
202
{
203 204
	struct drm_i915_private *i915 = ____uc_fw_to_gt(uc_fw, type)->i915;

205
	/*
206
	 * we use FIRMWARE_UNINITIALIZED to detect checks against uc_fw->status
207 208 209
	 * before we're looked at the HW caps to see if we have uc support
	 */
	BUILD_BUG_ON(INTEL_UC_FIRMWARE_UNINITIALIZED);
210
	GEM_BUG_ON(uc_fw->status);
211 212 213 214
	GEM_BUG_ON(uc_fw->path);

	uc_fw->type = type;

215 216 217 218
	if (HAS_GT_UC(i915)) {
		__uc_fw_auto_select(uc_fw,
				    INTEL_INFO(i915)->platform,
				    INTEL_REVID(i915));
219 220
		__uc_fw_user_override(uc_fw);
	}
221

222
	intel_uc_fw_change_status(uc_fw, uc_fw->path ? *uc_fw->path ?
223
				  INTEL_UC_FIRMWARE_SELECTED :
224
				  INTEL_UC_FIRMWARE_DISABLED :
225
				  INTEL_UC_FIRMWARE_NOT_SUPPORTED);
226 227
}

228
static void __force_fw_fetch_failures(struct intel_uc_fw *uc_fw, int e)
229
{
230
	struct drm_i915_private *i915 = __uc_fw_to_gt(uc_fw)->i915;
231 232
	bool user = e == -EINVAL;

233
	if (i915_inject_probe_error(i915, e)) {
234 235 236
		/* non-existing blob */
		uc_fw->path = "<invalid>";
		uc_fw->user_overridden = user;
237
	} else if (i915_inject_probe_error(i915, e)) {
238 239 240 241
		/* require next major version */
		uc_fw->major_ver_wanted += 1;
		uc_fw->minor_ver_wanted = 0;
		uc_fw->user_overridden = user;
242
	} else if (i915_inject_probe_error(i915, e)) {
243 244 245
		/* require next minor version */
		uc_fw->minor_ver_wanted += 1;
		uc_fw->user_overridden = user;
246 247
	} else if (uc_fw->major_ver_wanted &&
		   i915_inject_probe_error(i915, e)) {
248 249 250 251
		/* require prev major version */
		uc_fw->major_ver_wanted -= 1;
		uc_fw->minor_ver_wanted = 0;
		uc_fw->user_overridden = user;
252 253
	} else if (uc_fw->minor_ver_wanted &&
		   i915_inject_probe_error(i915, e)) {
254 255 256
		/* require prev minor version - hey, this should work! */
		uc_fw->minor_ver_wanted -= 1;
		uc_fw->user_overridden = user;
257
	} else if (user && i915_inject_probe_error(i915, e)) {
258 259 260 261 262 263 264
		/* officially unsupported platform */
		uc_fw->major_ver_wanted = 0;
		uc_fw->minor_ver_wanted = 0;
		uc_fw->user_overridden = true;
	}
}

265 266 267 268 269
/**
 * intel_uc_fw_fetch - fetch uC firmware
 * @uc_fw: uC firmware
 *
 * Fetch uC firmware into GEM obj.
270 271
 *
 * Return: 0 on success, a negative errno code on failure.
272
 */
273
int intel_uc_fw_fetch(struct intel_uc_fw *uc_fw)
274
{
275
	struct drm_i915_private *i915 = __uc_fw_to_gt(uc_fw)->i915;
276
	struct device *dev = i915->drm.dev;
277 278 279 280 281 282
	struct drm_i915_gem_object *obj;
	const struct firmware *fw = NULL;
	struct uc_css_header *css;
	size_t size;
	int err;

283
	GEM_BUG_ON(!i915->wopcm.size);
284
	GEM_BUG_ON(!intel_uc_fw_is_enabled(uc_fw));
285

286
	err = i915_inject_probe_error(i915, -ENXIO);
287
	if (err)
288
		goto fail;
289

290 291
	__force_fw_fetch_failures(uc_fw, -EINVAL);
	__force_fw_fetch_failures(uc_fw, -ESTALE);
292 293 294 295

	err = request_firmware(&fw, uc_fw->path, dev);
	if (err)
		goto fail;
296 297

	/* Check the size of the blob before examining buffer contents */
298
	if (unlikely(fw->size < sizeof(struct uc_css_header))) {
299
		drm_warn(&i915->drm, "%s firmware %s: invalid size: %zu < %zu\n",
300
			 intel_uc_fw_type_repr(uc_fw->type), uc_fw->path,
301 302
			 fw->size, sizeof(struct uc_css_header));
		err = -ENODATA;
303 304 305 306 307
		goto fail;
	}

	css = (struct uc_css_header *)fw->data;

308 309 310
	/* Check integrity of size values inside CSS header */
	size = (css->header_size_dw - css->key_size_dw - css->modulus_size_dw -
		css->exponent_size_dw) * sizeof(u32);
311
	if (unlikely(size != sizeof(struct uc_css_header))) {
312
		drm_warn(&i915->drm,
313 314 315 316
			 "%s firmware %s: unexpected header size: %zu != %zu\n",
			 intel_uc_fw_type_repr(uc_fw->type), uc_fw->path,
			 fw->size, sizeof(struct uc_css_header));
		err = -EPROTO;
317 318 319
		goto fail;
	}

320
	/* uCode size must calculated from other sizes */
321 322 323
	uc_fw->ucode_size = (css->size_dw - css->header_size_dw) * sizeof(u32);

	/* now RSA */
324
	if (unlikely(css->key_size_dw != UOS_RSA_SCRATCH_COUNT)) {
325
		drm_warn(&i915->drm, "%s firmware %s: unexpected key size: %u != %u\n",
326 327 328
			 intel_uc_fw_type_repr(uc_fw->type), uc_fw->path,
			 css->key_size_dw, UOS_RSA_SCRATCH_COUNT);
		err = -EPROTO;
329 330 331 332 333
		goto fail;
	}
	uc_fw->rsa_size = css->key_size_dw * sizeof(u32);

	/* At least, it should have header, uCode and RSA. Size of all three. */
334
	size = sizeof(struct uc_css_header) + uc_fw->ucode_size + uc_fw->rsa_size;
335
	if (unlikely(fw->size < size)) {
336
		drm_warn(&i915->drm, "%s firmware %s: invalid size: %zu < %zu\n",
337 338
			 intel_uc_fw_type_repr(uc_fw->type), uc_fw->path,
			 fw->size, size);
339
		err = -ENOEXEC;
340 341 342
		goto fail;
	}

343 344 345
	/* Sanity check whether this fw is not larger than whole WOPCM memory */
	size = __intel_uc_fw_get_upload_size(uc_fw);
	if (unlikely(size >= i915->wopcm.size)) {
346
		drm_warn(&i915->drm, "%s firmware %s: invalid size: %zu > %zu\n",
347 348 349 350 351 352
			 intel_uc_fw_type_repr(uc_fw->type), uc_fw->path,
			 size, (size_t)i915->wopcm.size);
		err = -E2BIG;
		goto fail;
	}

353
	/* Get version numbers from the CSS header */
354 355 356 357
	uc_fw->major_ver_found = FIELD_GET(CSS_SW_VERSION_UC_MAJOR,
					   css->sw_version);
	uc_fw->minor_ver_found = FIELD_GET(CSS_SW_VERSION_UC_MINOR,
					   css->sw_version);
358

359 360
	if (uc_fw->major_ver_found != uc_fw->major_ver_wanted ||
	    uc_fw->minor_ver_found < uc_fw->minor_ver_wanted) {
361
		drm_notice(&i915->drm, "%s firmware %s: unexpected version: %u.%u != %u.%u\n",
362 363 364 365 366 367 368
			   intel_uc_fw_type_repr(uc_fw->type), uc_fw->path,
			   uc_fw->major_ver_found, uc_fw->minor_ver_found,
			   uc_fw->major_ver_wanted, uc_fw->minor_ver_wanted);
		if (!intel_uc_fw_is_overridden(uc_fw)) {
			err = -ENOEXEC;
			goto fail;
		}
369 370
	}

371
	obj = i915_gem_object_create_shmem_from_data(i915, fw->data, fw->size);
372 373 374 375 376 377 378
	if (IS_ERR(obj)) {
		err = PTR_ERR(obj);
		goto fail;
	}

	uc_fw->obj = obj;
	uc_fw->size = fw->size;
379
	intel_uc_fw_change_status(uc_fw, INTEL_UC_FIRMWARE_AVAILABLE);
380

381
	release_firmware(fw);
382
	return 0;
383 384

fail:
385 386 387
	intel_uc_fw_change_status(uc_fw, err == -ENOENT ?
				  INTEL_UC_FIRMWARE_MISSING :
				  INTEL_UC_FIRMWARE_ERROR);
388

389
	drm_notice(&i915->drm, "%s firmware %s: fetch failed with error %d\n",
390
		   intel_uc_fw_type_repr(uc_fw->type), uc_fw->path, err);
391
	drm_info(&i915->drm, "%s firmware(s) can be downloaded from %s\n",
392
		 intel_uc_fw_type_repr(uc_fw->type), INTEL_UC_FIRMWARE_URL);
393 394

	release_firmware(fw);		/* OK even if fw is NULL */
395
	return err;
396 397
}

398
static u32 uc_fw_ggtt_offset(struct intel_uc_fw *uc_fw)
399
{
400
	struct i915_ggtt *ggtt = __uc_fw_to_gt(uc_fw)->ggtt;
401 402
	struct drm_mm_node *node = &ggtt->uc_fw;

403
	GEM_BUG_ON(!drm_mm_node_allocated(node));
404 405 406 407 408 409
	GEM_BUG_ON(upper_32_bits(node->start));
	GEM_BUG_ON(upper_32_bits(node->start + node->size - 1));

	return lower_32_bits(node->start);
}

410
static void uc_fw_bind_ggtt(struct intel_uc_fw *uc_fw)
411 412
{
	struct drm_i915_gem_object *obj = uc_fw->obj;
413
	struct i915_ggtt *ggtt = __uc_fw_to_gt(uc_fw)->ggtt;
414
	struct i915_vma dummy = {
415
		.node.start = uc_fw_ggtt_offset(uc_fw),
416 417 418 419 420 421 422 423 424 425 426 427 428 429
		.node.size = obj->base.size,
		.pages = obj->mm.pages,
		.vm = &ggtt->vm,
	};

	GEM_BUG_ON(!i915_gem_object_has_pinned_pages(obj));
	GEM_BUG_ON(dummy.node.size > ggtt->uc_fw.size);

	/* uc_fw->obj cache domains were not controlled across suspend */
	drm_clflush_sg(dummy.pages);

	ggtt->vm.insert_entries(&ggtt->vm, &dummy, I915_CACHE_NONE, 0);
}

430
static void uc_fw_unbind_ggtt(struct intel_uc_fw *uc_fw)
431 432
{
	struct drm_i915_gem_object *obj = uc_fw->obj;
433
	struct i915_ggtt *ggtt = __uc_fw_to_gt(uc_fw)->ggtt;
434
	u64 start = uc_fw_ggtt_offset(uc_fw);
435 436 437 438

	ggtt->vm.clear_range(&ggtt->vm, start, obj->base.size);
}

439
static int uc_fw_xfer(struct intel_uc_fw *uc_fw, u32 dst_offset, u32 dma_flags)
440
{
441
	struct intel_gt *gt = __uc_fw_to_gt(uc_fw);
442 443 444 445
	struct intel_uncore *uncore = gt->uncore;
	u64 offset;
	int ret;

446
	ret = i915_inject_probe_error(gt->i915, -ETIMEDOUT);
447 448 449
	if (ret)
		return ret;

450 451 452
	intel_uncore_forcewake_get(uncore, FORCEWAKE_ALL);

	/* Set the source address for the uCode */
453
	offset = uc_fw_ggtt_offset(uc_fw);
454 455 456 457 458
	GEM_BUG_ON(upper_32_bits(offset) & 0xFFFF0000);
	intel_uncore_write_fw(uncore, DMA_ADDR_0_LOW, lower_32_bits(offset));
	intel_uncore_write_fw(uncore, DMA_ADDR_0_HIGH, upper_32_bits(offset));

	/* Set the DMA destination */
459
	intel_uncore_write_fw(uncore, DMA_ADDR_1_LOW, dst_offset);
460 461 462 463 464 465 466
	intel_uncore_write_fw(uncore, DMA_ADDR_1_HIGH, DMA_ADDRESS_SPACE_WOPCM);

	/*
	 * Set the transfer size. The header plus uCode will be copied to WOPCM
	 * via DMA, excluding any other components
	 */
	intel_uncore_write_fw(uncore, DMA_COPY_SIZE,
467
			      sizeof(struct uc_css_header) + uc_fw->ucode_size);
468 469 470 471 472 473 474 475

	/* Start the DMA */
	intel_uncore_write_fw(uncore, DMA_CTRL,
			      _MASKED_BIT_ENABLE(dma_flags | START_DMA));

	/* Wait for DMA to finish */
	ret = intel_wait_for_register_fw(uncore, DMA_CTRL, START_DMA, 0, 100);
	if (ret)
476
		drm_err(&gt->i915->drm, "DMA for %s fw failed, DMA_CTRL=%u\n",
477 478 479 480 481 482 483 484 485 486 487
			intel_uc_fw_type_repr(uc_fw->type),
			intel_uncore_read_fw(uncore, DMA_CTRL));

	/* Disable the bits once DMA is over */
	intel_uncore_write_fw(uncore, DMA_CTRL, _MASKED_BIT_DISABLE(dma_flags));

	intel_uncore_forcewake_put(uncore, FORCEWAKE_ALL);

	return ret;
}

488 489 490
/**
 * intel_uc_fw_upload - load uC firmware using custom loader
 * @uc_fw: uC firmware
491
 * @dst_offset: destination offset
492
 * @dma_flags: flags for flags for dma ctrl
493
 *
494
 * Loads uC firmware and updates internal flags.
495 496
 *
 * Return: 0 on success, non-zero on failure.
497
 */
498
int intel_uc_fw_upload(struct intel_uc_fw *uc_fw, u32 dst_offset, u32 dma_flags)
499
{
500
	struct intel_gt *gt = __uc_fw_to_gt(uc_fw);
501 502
	int err;

503 504
	/* make sure the status was cleared the last time we reset the uc */
	GEM_BUG_ON(intel_uc_fw_is_loaded(uc_fw));
505

506
	err = i915_inject_probe_error(gt->i915, -ENOEXEC);
507 508 509
	if (err)
		return err;

510
	if (!intel_uc_fw_is_loadable(uc_fw))
511
		return -ENOEXEC;
512

513
	/* Call custom loader */
514 515 516
	uc_fw_bind_ggtt(uc_fw);
	err = uc_fw_xfer(uc_fw, dst_offset, dma_flags);
	uc_fw_unbind_ggtt(uc_fw);
517 518 519
	if (err)
		goto fail;

520
	intel_uc_fw_change_status(uc_fw, INTEL_UC_FIRMWARE_TRANSFERRED);
521 522 523
	return 0;

fail:
524 525 526
	i915_probe_error(gt->i915, "Failed to load %s firmware %s (%d)\n",
			 intel_uc_fw_type_repr(uc_fw->type), uc_fw->path,
			 err);
527
	intel_uc_fw_change_status(uc_fw, INTEL_UC_FIRMWARE_FAIL);
528 529 530
	return err;
}

531 532 533 534
int intel_uc_fw_init(struct intel_uc_fw *uc_fw)
{
	int err;

535 536 537 538
	/* this should happen before the load! */
	GEM_BUG_ON(intel_uc_fw_is_loaded(uc_fw));

	if (!intel_uc_fw_is_available(uc_fw))
539 540 541
		return -ENOEXEC;

	err = i915_gem_object_pin_pages(uc_fw->obj);
542
	if (err) {
543 544
		DRM_DEBUG_DRIVER("%s fw pin-pages err=%d\n",
				 intel_uc_fw_type_repr(uc_fw->type), err);
545 546
		intel_uc_fw_change_status(uc_fw, INTEL_UC_FIRMWARE_FAIL);
	}
547 548 549 550 551 552

	return err;
}

void intel_uc_fw_fini(struct intel_uc_fw *uc_fw)
{
553 554 555 556
	if (i915_gem_object_has_pinned_pages(uc_fw->obj))
		i915_gem_object_unpin_pages(uc_fw->obj);

	intel_uc_fw_change_status(uc_fw, INTEL_UC_FIRMWARE_AVAILABLE);
557 558
}

559
/**
560
 * intel_uc_fw_cleanup_fetch - cleanup uC firmware
561 562 563 564
 * @uc_fw: uC firmware
 *
 * Cleans up uC firmware by releasing the firmware GEM obj.
 */
565
void intel_uc_fw_cleanup_fetch(struct intel_uc_fw *uc_fw)
566
{
567 568
	if (!intel_uc_fw_is_available(uc_fw))
		return;
569

570
	i915_gem_object_put(fetch_and_zero(&uc_fw->obj));
571

572
	intel_uc_fw_change_status(uc_fw, INTEL_UC_FIRMWARE_SELECTED);
573
}
574

575 576 577 578 579 580 581 582 583 584 585 586 587
/**
 * intel_uc_fw_copy_rsa - copy fw RSA to buffer
 *
 * @uc_fw: uC firmware
 * @dst: dst buffer
 * @max_len: max number of bytes to copy
 *
 * Return: number of copied bytes.
 */
size_t intel_uc_fw_copy_rsa(struct intel_uc_fw *uc_fw, void *dst, u32 max_len)
{
	struct sg_table *pages = uc_fw->obj->mm.pages;
	u32 size = min_t(u32, uc_fw->rsa_size, max_len);
588
	u32 offset = sizeof(struct uc_css_header) + uc_fw->ucode_size;
589 590 591

	GEM_BUG_ON(!intel_uc_fw_is_available(uc_fw));

592
	return sg_pcopy_to_buffer(pages->sgl, pages->nents, dst, size, offset);
593 594
}

595 596 597 598 599 600 601
/**
 * intel_uc_fw_dump - dump information about uC firmware
 * @uc_fw: uC firmware
 * @p: the &drm_printer
 *
 * Pretty printer for uC firmware.
 */
602
void intel_uc_fw_dump(const struct intel_uc_fw *uc_fw, struct drm_printer *p)
603 604 605
{
	drm_printf(p, "%s firmware: %s\n",
		   intel_uc_fw_type_repr(uc_fw->type), uc_fw->path);
606 607
	drm_printf(p, "\tstatus: %s\n",
		   intel_uc_fw_status_repr(uc_fw->status));
608 609 610
	drm_printf(p, "\tversion: wanted %u.%u, found %u.%u\n",
		   uc_fw->major_ver_wanted, uc_fw->minor_ver_wanted,
		   uc_fw->major_ver_found, uc_fw->minor_ver_found);
611
	drm_printf(p, "\tuCode: %u bytes\n", uc_fw->ucode_size);
612
	drm_printf(p, "\tRSA: %u bytes\n", uc_fw->rsa_size);
613
}