1 /*
2  * Copyright © 2016-2017 Intel Corporation
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a
5  * copy of this software and associated documentation files (the "Software"),
6  * to deal in the Software without restriction, including without limitation
7  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8  * and/or sell copies of the Software, and to permit persons to whom the
9  * Software is furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice (including the next
12  * paragraph) shall be included in all copies or substantial portions of the
13  * Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
21  * IN THE SOFTWARE.
22  *
23  */
24 
25 #include <linux/bitfield.h>
26 #include <linux/firmware.h>
27 #include <drm/drm_print.h>
28 
29 #include "intel_uc_fw.h"
30 #include "intel_uc_fw_abi.h"
31 #include "i915_drv.h"
32 
33 /*
34  * List of required GuC and HuC binaries per-platform.
35  * Must be ordered based on platform + revid, from newer to older.
36  */
37 #define INTEL_UC_FIRMWARE_DEFS(fw_def, guc_def, huc_def) \
38 	fw_def(ICELAKE,    0, guc_def(icl, 33, 0, 0), huc_def(icl,  8,  4, 3238)) \
39 	fw_def(COFFEELAKE, 0, guc_def(kbl, 33, 0, 0), huc_def(kbl, 02, 00, 1810)) \
40 	fw_def(GEMINILAKE, 0, guc_def(glk, 33, 0, 0), huc_def(glk, 03, 01, 2893)) \
41 	fw_def(KABYLAKE,   0, guc_def(kbl, 33, 0, 0), huc_def(kbl, 02, 00, 1810)) \
42 	fw_def(BROXTON,    0, guc_def(bxt, 33, 0, 0), huc_def(bxt, 01,  8, 2893)) \
43 	fw_def(SKYLAKE,    0, guc_def(skl, 33, 0, 0), huc_def(skl, 01, 07, 1398))
44 
45 #define __MAKE_UC_FW_PATH(prefix_, name_, separator_, major_, minor_, patch_) \
46 	"i915/" \
47 	__stringify(prefix_) name_ \
48 	__stringify(major_) separator_ \
49 	__stringify(minor_) separator_ \
50 	__stringify(patch_) ".bin"
51 
52 #define MAKE_GUC_FW_PATH(prefix_, major_, minor_, patch_) \
53 	__MAKE_UC_FW_PATH(prefix_, "_guc_", ".", major_, minor_, patch_)
54 
55 #define MAKE_HUC_FW_PATH(prefix_, major_, minor_, bld_num_) \
56 	__MAKE_UC_FW_PATH(prefix_, "_huc_ver", "_", major_, minor_, bld_num_)
57 
58 /* All blobs need to be declared via MODULE_FIRMWARE() */
59 #define INTEL_UC_MODULE_FW(platform_, revid_, guc_, huc_) \
60 	MODULE_FIRMWARE(guc_); \
61 	MODULE_FIRMWARE(huc_);
62 
63 INTEL_UC_FIRMWARE_DEFS(INTEL_UC_MODULE_FW, MAKE_GUC_FW_PATH, MAKE_HUC_FW_PATH)
64 
65 /* The below structs and macros are used to iterate across the list of blobs */
66 struct __packed uc_fw_blob {
67 	u8 major;
68 	u8 minor;
69 	const char *path;
70 };
71 
72 #define UC_FW_BLOB(major_, minor_, path_) \
73 	{ .major = major_, .minor = minor_, .path = path_ }
74 
75 #define GUC_FW_BLOB(prefix_, major_, minor_, patch_) \
76 	UC_FW_BLOB(major_, minor_, \
77 		   MAKE_GUC_FW_PATH(prefix_, major_, minor_, patch_))
78 
79 #define HUC_FW_BLOB(prefix_, major_, minor_, bld_num_) \
80 	UC_FW_BLOB(major_, minor_, \
81 		   MAKE_HUC_FW_PATH(prefix_, major_, minor_, bld_num_))
82 
83 struct __packed uc_fw_platform_requirement {
84 	enum intel_platform p;
85 	u8 rev; /* first platform rev using this FW */
86 	const struct uc_fw_blob blobs[INTEL_UC_FW_NUM_TYPES];
87 };
88 
89 #define MAKE_FW_LIST(platform_, revid_, guc_, huc_) \
90 { \
91 	.p = INTEL_##platform_, \
92 	.rev = revid_, \
93 	.blobs[INTEL_UC_FW_TYPE_GUC] = guc_, \
94 	.blobs[INTEL_UC_FW_TYPE_HUC] = huc_, \
95 },
96 
97 static void
98 __uc_fw_auto_select(struct intel_uc_fw *uc_fw, enum intel_platform p, u8 rev)
99 {
100 	static const struct uc_fw_platform_requirement fw_blobs[] = {
101 		INTEL_UC_FIRMWARE_DEFS(MAKE_FW_LIST, GUC_FW_BLOB, HUC_FW_BLOB)
102 	};
103 	int i;
104 
105 	for (i = 0; i < ARRAY_SIZE(fw_blobs) && p <= fw_blobs[i].p; i++) {
106 		if (p == fw_blobs[i].p && rev >= fw_blobs[i].rev) {
107 			const struct uc_fw_blob *blob =
108 					&fw_blobs[i].blobs[uc_fw->type];
109 			uc_fw->path = blob->path;
110 			uc_fw->major_ver_wanted = blob->major;
111 			uc_fw->minor_ver_wanted = blob->minor;
112 			break;
113 		}
114 	}
115 
116 	/* make sure the list is ordered as expected */
117 	if (IS_ENABLED(CONFIG_DRM_I915_SELFTEST)) {
118 		for (i = 1; i < ARRAY_SIZE(fw_blobs); i++) {
119 			if (fw_blobs[i].p < fw_blobs[i - 1].p)
120 				continue;
121 
122 			if (fw_blobs[i].p == fw_blobs[i - 1].p &&
123 			    fw_blobs[i].rev < fw_blobs[i - 1].rev)
124 				continue;
125 
126 			pr_err("invalid FW blob order: %s r%u comes before %s r%u\n",
127 			       intel_platform_name(fw_blobs[i - 1].p),
128 			       fw_blobs[i - 1].rev,
129 			       intel_platform_name(fw_blobs[i].p),
130 			       fw_blobs[i].rev);
131 
132 			uc_fw->path = NULL;
133 		}
134 	}
135 }
136 
137 static bool
138 __uc_fw_override(struct intel_uc_fw *uc_fw)
139 {
140 	switch (uc_fw->type) {
141 	case INTEL_UC_FW_TYPE_GUC:
142 		uc_fw->path = i915_modparams.guc_firmware_path;
143 		break;
144 	case INTEL_UC_FW_TYPE_HUC:
145 		uc_fw->path = i915_modparams.huc_firmware_path;
146 		break;
147 	}
148 
149 	uc_fw->user_overridden = uc_fw->path;
150 	return uc_fw->user_overridden;
151 }
152 
153 /**
154  * intel_uc_fw_init_early - initialize the uC object and select the firmware
155  * @i915: device private
156  * @uc_fw: uC firmware
157  * @type: type of uC
158  *
159  * Initialize the state of our uC object and relevant tracking and select the
160  * firmware to fetch and load.
161  */
162 void intel_uc_fw_init_early(struct intel_uc_fw *uc_fw,
163 			    enum intel_uc_fw_type type,
164 			    struct drm_i915_private *i915)
165 {
166 	/*
167 	 * we use FIRMWARE_UNINITIALIZED to detect checks against uc_fw->status
168 	 * before we're looked at the HW caps to see if we have uc support
169 	 */
170 	BUILD_BUG_ON(INTEL_UC_FIRMWARE_UNINITIALIZED);
171 	GEM_BUG_ON(uc_fw->status);
172 	GEM_BUG_ON(uc_fw->path);
173 
174 	uc_fw->type = type;
175 
176 	if (HAS_GT_UC(i915) && likely(!__uc_fw_override(uc_fw)))
177 		__uc_fw_auto_select(uc_fw, INTEL_INFO(i915)->platform,
178 				    INTEL_REVID(i915));
179 
180 	if (uc_fw->path && *uc_fw->path)
181 		uc_fw->status = INTEL_UC_FIRMWARE_SELECTED;
182 	else
183 		uc_fw->status = INTEL_UC_FIRMWARE_NOT_SUPPORTED;
184 }
185 
186 /**
187  * intel_uc_fw_fetch - fetch uC firmware
188  *
189  * @uc_fw: uC firmware
190  * @i915: device private
191  *
192  * Fetch uC firmware into GEM obj.
193  */
194 void intel_uc_fw_fetch(struct intel_uc_fw *uc_fw, struct drm_i915_private *i915)
195 {
196 	struct drm_i915_gem_object *obj;
197 	const struct firmware *fw = NULL;
198 	struct uc_css_header *css;
199 	size_t size;
200 	int err;
201 
202 	GEM_BUG_ON(!intel_uc_fw_supported(uc_fw));
203 
204 	err = request_firmware(&fw, uc_fw->path, i915->drm.dev);
205 	if (err)
206 		goto fail;
207 
208 	DRM_DEBUG_DRIVER("%s fw size %zu ptr %p\n",
209 			 intel_uc_fw_type_repr(uc_fw->type), fw->size, fw);
210 
211 	/* Check the size of the blob before examining buffer contents */
212 	if (fw->size < sizeof(struct uc_css_header)) {
213 		DRM_WARN("%s: Unexpected firmware size (%zu, min %zu)\n",
214 			 intel_uc_fw_type_repr(uc_fw->type),
215 			 fw->size, sizeof(struct uc_css_header));
216 		err = -ENODATA;
217 		goto fail;
218 	}
219 
220 	css = (struct uc_css_header *)fw->data;
221 
222 	/* Check integrity of size values inside CSS header */
223 	size = (css->header_size_dw - css->key_size_dw - css->modulus_size_dw -
224 		css->exponent_size_dw) * sizeof(u32);
225 	if (size != sizeof(struct uc_css_header)) {
226 		DRM_WARN("%s: Mismatched firmware header definition\n",
227 			 intel_uc_fw_type_repr(uc_fw->type));
228 		err = -ENOEXEC;
229 		goto fail;
230 	}
231 
232 	/* uCode size must calculated from other sizes */
233 	uc_fw->ucode_size = (css->size_dw - css->header_size_dw) * sizeof(u32);
234 
235 	/* now RSA */
236 	if (css->key_size_dw != UOS_RSA_SCRATCH_COUNT) {
237 		DRM_WARN("%s: Mismatched firmware RSA key size (%u)\n",
238 			 intel_uc_fw_type_repr(uc_fw->type), css->key_size_dw);
239 		err = -ENOEXEC;
240 		goto fail;
241 	}
242 	uc_fw->rsa_size = css->key_size_dw * sizeof(u32);
243 
244 	/* At least, it should have header, uCode and RSA. Size of all three. */
245 	size = sizeof(struct uc_css_header) + uc_fw->ucode_size + uc_fw->rsa_size;
246 	if (fw->size < size) {
247 		DRM_WARN("%s: Truncated firmware (%zu, expected %zu)\n",
248 			 intel_uc_fw_type_repr(uc_fw->type), fw->size, size);
249 		err = -ENOEXEC;
250 		goto fail;
251 	}
252 
253 	/* Get version numbers from the CSS header */
254 	switch (uc_fw->type) {
255 	case INTEL_UC_FW_TYPE_GUC:
256 		uc_fw->major_ver_found = FIELD_GET(CSS_SW_VERSION_GUC_MAJOR,
257 						   css->sw_version);
258 		uc_fw->minor_ver_found = FIELD_GET(CSS_SW_VERSION_GUC_MINOR,
259 						   css->sw_version);
260 		break;
261 
262 	case INTEL_UC_FW_TYPE_HUC:
263 		uc_fw->major_ver_found = FIELD_GET(CSS_SW_VERSION_HUC_MAJOR,
264 						   css->sw_version);
265 		uc_fw->minor_ver_found = FIELD_GET(CSS_SW_VERSION_HUC_MINOR,
266 						   css->sw_version);
267 		break;
268 
269 	default:
270 		MISSING_CASE(uc_fw->type);
271 		break;
272 	}
273 
274 	DRM_DEBUG_DRIVER("%s fw version %u.%u (wanted %u.%u)\n",
275 			 intel_uc_fw_type_repr(uc_fw->type),
276 			 uc_fw->major_ver_found, uc_fw->minor_ver_found,
277 			 uc_fw->major_ver_wanted, uc_fw->minor_ver_wanted);
278 
279 	if (uc_fw->major_ver_wanted == 0 && uc_fw->minor_ver_wanted == 0) {
280 		DRM_NOTE("%s: Skipping firmware version check\n",
281 			 intel_uc_fw_type_repr(uc_fw->type));
282 	} else if (uc_fw->major_ver_found != uc_fw->major_ver_wanted ||
283 		   uc_fw->minor_ver_found < uc_fw->minor_ver_wanted) {
284 		DRM_NOTE("%s: Wrong firmware version (%u.%u, required %u.%u)\n",
285 			 intel_uc_fw_type_repr(uc_fw->type),
286 			 uc_fw->major_ver_found, uc_fw->minor_ver_found,
287 			 uc_fw->major_ver_wanted, uc_fw->minor_ver_wanted);
288 		err = -ENOEXEC;
289 		goto fail;
290 	}
291 
292 	obj = i915_gem_object_create_shmem_from_data(i915, fw->data, fw->size);
293 	if (IS_ERR(obj)) {
294 		err = PTR_ERR(obj);
295 		DRM_DEBUG_DRIVER("%s fw object_create err=%d\n",
296 				 intel_uc_fw_type_repr(uc_fw->type), err);
297 		goto fail;
298 	}
299 
300 	uc_fw->obj = obj;
301 	uc_fw->size = fw->size;
302 	uc_fw->status = INTEL_UC_FIRMWARE_AVAILABLE;
303 
304 	release_firmware(fw);
305 	return;
306 
307 fail:
308 	uc_fw->status = INTEL_UC_FIRMWARE_MISSING;
309 
310 	DRM_WARN("%s: Failed to fetch firmware %s (error %d)\n",
311 		 intel_uc_fw_type_repr(uc_fw->type), uc_fw->path, err);
312 	DRM_INFO("%s: Firmware can be downloaded from %s\n",
313 		 intel_uc_fw_type_repr(uc_fw->type), INTEL_UC_FIRMWARE_URL);
314 
315 	release_firmware(fw);		/* OK even if fw is NULL */
316 }
317 
318 static u32 uc_fw_ggtt_offset(struct intel_uc_fw *uc_fw, struct i915_ggtt *ggtt)
319 {
320 	struct drm_mm_node *node = &ggtt->uc_fw;
321 
322 	GEM_BUG_ON(!node->allocated);
323 	GEM_BUG_ON(upper_32_bits(node->start));
324 	GEM_BUG_ON(upper_32_bits(node->start + node->size - 1));
325 
326 	return lower_32_bits(node->start);
327 }
328 
329 static void intel_uc_fw_ggtt_bind(struct intel_uc_fw *uc_fw,
330 				  struct intel_gt *gt)
331 {
332 	struct drm_i915_gem_object *obj = uc_fw->obj;
333 	struct i915_ggtt *ggtt = gt->ggtt;
334 	struct i915_vma dummy = {
335 		.node.start = uc_fw_ggtt_offset(uc_fw, ggtt),
336 		.node.size = obj->base.size,
337 		.pages = obj->mm.pages,
338 		.vm = &ggtt->vm,
339 	};
340 
341 	GEM_BUG_ON(!i915_gem_object_has_pinned_pages(obj));
342 	GEM_BUG_ON(dummy.node.size > ggtt->uc_fw.size);
343 
344 	/* uc_fw->obj cache domains were not controlled across suspend */
345 	drm_clflush_sg(dummy.pages);
346 
347 	ggtt->vm.insert_entries(&ggtt->vm, &dummy, I915_CACHE_NONE, 0);
348 }
349 
350 static void intel_uc_fw_ggtt_unbind(struct intel_uc_fw *uc_fw,
351 				    struct intel_gt *gt)
352 {
353 	struct drm_i915_gem_object *obj = uc_fw->obj;
354 	struct i915_ggtt *ggtt = gt->ggtt;
355 	u64 start = uc_fw_ggtt_offset(uc_fw, ggtt);
356 
357 	ggtt->vm.clear_range(&ggtt->vm, start, obj->base.size);
358 }
359 
360 static int uc_fw_xfer(struct intel_uc_fw *uc_fw, struct intel_gt *gt,
361 		      u32 wopcm_offset, u32 dma_flags)
362 {
363 	struct intel_uncore *uncore = gt->uncore;
364 	u64 offset;
365 	int ret;
366 
367 	intel_uncore_forcewake_get(uncore, FORCEWAKE_ALL);
368 
369 	/* Set the source address for the uCode */
370 	offset = uc_fw_ggtt_offset(uc_fw, gt->ggtt);
371 	GEM_BUG_ON(upper_32_bits(offset) & 0xFFFF0000);
372 	intel_uncore_write_fw(uncore, DMA_ADDR_0_LOW, lower_32_bits(offset));
373 	intel_uncore_write_fw(uncore, DMA_ADDR_0_HIGH, upper_32_bits(offset));
374 
375 	/* Set the DMA destination */
376 	intel_uncore_write_fw(uncore, DMA_ADDR_1_LOW, wopcm_offset);
377 	intel_uncore_write_fw(uncore, DMA_ADDR_1_HIGH, DMA_ADDRESS_SPACE_WOPCM);
378 
379 	/*
380 	 * Set the transfer size. The header plus uCode will be copied to WOPCM
381 	 * via DMA, excluding any other components
382 	 */
383 	intel_uncore_write_fw(uncore, DMA_COPY_SIZE,
384 			      sizeof(struct uc_css_header) + uc_fw->ucode_size);
385 
386 	/* Start the DMA */
387 	intel_uncore_write_fw(uncore, DMA_CTRL,
388 			      _MASKED_BIT_ENABLE(dma_flags | START_DMA));
389 
390 	/* Wait for DMA to finish */
391 	ret = intel_wait_for_register_fw(uncore, DMA_CTRL, START_DMA, 0, 100);
392 	if (ret)
393 		dev_err(gt->i915->drm.dev, "DMA for %s fw failed, DMA_CTRL=%u\n",
394 			intel_uc_fw_type_repr(uc_fw->type),
395 			intel_uncore_read_fw(uncore, DMA_CTRL));
396 
397 	/* Disable the bits once DMA is over */
398 	intel_uncore_write_fw(uncore, DMA_CTRL, _MASKED_BIT_DISABLE(dma_flags));
399 
400 	intel_uncore_forcewake_put(uncore, FORCEWAKE_ALL);
401 
402 	return ret;
403 }
404 
405 /**
406  * intel_uc_fw_upload - load uC firmware using custom loader
407  * @uc_fw: uC firmware
408  * @gt: the intel_gt structure
409  * @wopcm_offset: destination offset in wopcm
410  * @dma_flags: flags for flags for dma ctrl
411  *
412  * Loads uC firmware and updates internal flags.
413  *
414  * Return: 0 on success, non-zero on failure.
415  */
416 int intel_uc_fw_upload(struct intel_uc_fw *uc_fw, struct intel_gt *gt,
417 		       u32 wopcm_offset, u32 dma_flags)
418 {
419 	int err;
420 
421 	DRM_DEBUG_DRIVER("%s fw load %s\n",
422 			 intel_uc_fw_type_repr(uc_fw->type), uc_fw->path);
423 
424 	/* make sure the status was cleared the last time we reset the uc */
425 	GEM_BUG_ON(intel_uc_fw_is_loaded(uc_fw));
426 
427 	if (!intel_uc_fw_is_available(uc_fw))
428 		return -ENOEXEC;
429 	/* Call custom loader */
430 	intel_uc_fw_ggtt_bind(uc_fw, gt);
431 	err = uc_fw_xfer(uc_fw, gt, wopcm_offset, dma_flags);
432 	intel_uc_fw_ggtt_unbind(uc_fw, gt);
433 	if (err)
434 		goto fail;
435 
436 	uc_fw->status = INTEL_UC_FIRMWARE_TRANSFERRED;
437 	DRM_DEBUG_DRIVER("%s fw xfer completed\n",
438 			 intel_uc_fw_type_repr(uc_fw->type));
439 
440 	DRM_INFO("%s: Loaded firmware %s (version %u.%u)\n",
441 		 intel_uc_fw_type_repr(uc_fw->type),
442 		 uc_fw->path,
443 		 uc_fw->major_ver_found, uc_fw->minor_ver_found);
444 
445 	return 0;
446 
447 fail:
448 	uc_fw->status = INTEL_UC_FIRMWARE_FAIL;
449 	DRM_DEBUG_DRIVER("%s fw load failed\n",
450 			 intel_uc_fw_type_repr(uc_fw->type));
451 
452 	DRM_WARN("%s: Failed to load firmware %s (error %d)\n",
453 		 intel_uc_fw_type_repr(uc_fw->type), uc_fw->path, err);
454 
455 	return err;
456 }
457 
458 int intel_uc_fw_init(struct intel_uc_fw *uc_fw)
459 {
460 	int err;
461 
462 	/* this should happen before the load! */
463 	GEM_BUG_ON(intel_uc_fw_is_loaded(uc_fw));
464 
465 	if (!intel_uc_fw_is_available(uc_fw))
466 		return -ENOEXEC;
467 
468 	err = i915_gem_object_pin_pages(uc_fw->obj);
469 	if (err)
470 		DRM_DEBUG_DRIVER("%s fw pin-pages err=%d\n",
471 				 intel_uc_fw_type_repr(uc_fw->type), err);
472 
473 	return err;
474 }
475 
476 void intel_uc_fw_fini(struct intel_uc_fw *uc_fw)
477 {
478 	if (!intel_uc_fw_is_available(uc_fw))
479 		return;
480 
481 	i915_gem_object_unpin_pages(uc_fw->obj);
482 }
483 
484 /**
485  * intel_uc_fw_cleanup_fetch - cleanup uC firmware
486  *
487  * @uc_fw: uC firmware
488  *
489  * Cleans up uC firmware by releasing the firmware GEM obj.
490  */
491 void intel_uc_fw_cleanup_fetch(struct intel_uc_fw *uc_fw)
492 {
493 	struct drm_i915_gem_object *obj;
494 
495 	obj = fetch_and_zero(&uc_fw->obj);
496 	if (obj)
497 		i915_gem_object_put(obj);
498 
499 	uc_fw->status = INTEL_UC_FIRMWARE_SELECTED;
500 }
501 
502 /**
503  * intel_uc_fw_copy_rsa - copy fw RSA to buffer
504  *
505  * @uc_fw: uC firmware
506  * @dst: dst buffer
507  * @max_len: max number of bytes to copy
508  *
509  * Return: number of copied bytes.
510  */
511 size_t intel_uc_fw_copy_rsa(struct intel_uc_fw *uc_fw, void *dst, u32 max_len)
512 {
513 	struct sg_table *pages = uc_fw->obj->mm.pages;
514 	u32 size = min_t(u32, uc_fw->rsa_size, max_len);
515 	u32 offset = sizeof(struct uc_css_header) + uc_fw->ucode_size;
516 
517 	GEM_BUG_ON(!intel_uc_fw_is_available(uc_fw));
518 
519 	return sg_pcopy_to_buffer(pages->sgl, pages->nents, dst, size, offset);
520 }
521 
522 /**
523  * intel_uc_fw_dump - dump information about uC firmware
524  * @uc_fw: uC firmware
525  * @p: the &drm_printer
526  *
527  * Pretty printer for uC firmware.
528  */
529 void intel_uc_fw_dump(const struct intel_uc_fw *uc_fw, struct drm_printer *p)
530 {
531 	drm_printf(p, "%s firmware: %s\n",
532 		   intel_uc_fw_type_repr(uc_fw->type), uc_fw->path);
533 	drm_printf(p, "\tstatus: %s\n",
534 		   intel_uc_fw_status_repr(uc_fw->status));
535 	drm_printf(p, "\tversion: wanted %u.%u, found %u.%u\n",
536 		   uc_fw->major_ver_wanted, uc_fw->minor_ver_wanted,
537 		   uc_fw->major_ver_found, uc_fw->minor_ver_found);
538 	drm_printf(p, "\tuCode: %u bytes\n", uc_fw->ucode_size);
539 	drm_printf(p, "\tRSA: %u bytes\n", uc_fw->rsa_size);
540 }
541