xref: /linux/drivers/gpu/drm/xe/xe_uc_fw.c (revision 94324e6bed4b5d973c0df5d2d7d0f50503306a28)
1dd08ebf6SMatthew Brost // SPDX-License-Identifier: MIT
2dd08ebf6SMatthew Brost /*
3dd08ebf6SMatthew Brost  * Copyright © 2022 Intel Corporation
4dd08ebf6SMatthew Brost  */
5dd08ebf6SMatthew Brost 
6dd08ebf6SMatthew Brost #include <linux/bitfield.h>
7dd08ebf6SMatthew Brost #include <linux/firmware.h>
8dd08ebf6SMatthew Brost 
9dd08ebf6SMatthew Brost #include <drm/drm_managed.h>
10dd08ebf6SMatthew Brost 
11dd08ebf6SMatthew Brost #include "xe_bo.h"
12dd08ebf6SMatthew Brost #include "xe_device_types.h"
13dd08ebf6SMatthew Brost #include "xe_force_wake.h"
14dd08ebf6SMatthew Brost #include "xe_gt.h"
15dd08ebf6SMatthew Brost #include "xe_guc_reg.h"
16dd08ebf6SMatthew Brost #include "xe_map.h"
17dd08ebf6SMatthew Brost #include "xe_mmio.h"
18dd08ebf6SMatthew Brost #include "xe_uc_fw.h"
19dd08ebf6SMatthew Brost 
20ad55ead7SLucas De Marchi /*
21ad55ead7SLucas De Marchi  * List of required GuC and HuC binaries per-platform. They must be ordered
22ad55ead7SLucas De Marchi  * based on platform, from newer to older.
23ad55ead7SLucas De Marchi  *
24ad55ead7SLucas De Marchi  * Versioning follows the guidelines from
25ad55ead7SLucas De Marchi  * Documentation/driver-api/firmware/firmware-usage-guidelines.rst. There is a
26ad55ead7SLucas De Marchi  * distinction for platforms being officially supported by the driver or not.
27ad55ead7SLucas De Marchi  * Platforms not available publicly or not yet officially supported by the
28ad55ead7SLucas De Marchi  * driver (under force-probe), use the mmp_ver(): the firmware autoselect logic
29ad55ead7SLucas De Marchi  * will select the firmware from disk with filename that matches the full
30ad55ead7SLucas De Marchi  * "mpp version", i.e. major.minor.patch. mmp_ver() should only be used for
31ad55ead7SLucas De Marchi  * this case.
32ad55ead7SLucas De Marchi  *
33ad55ead7SLucas De Marchi  * For platforms officially supported by the driver, the filename always only
34ad55ead7SLucas De Marchi  * ever contains the major version (GuC) or no version at all (HuC).
35ad55ead7SLucas De Marchi  *
36ad55ead7SLucas De Marchi  * After loading the file, the driver parses the versions embedded in the blob.
37ad55ead7SLucas De Marchi  * The major version needs to match a major version supported by the driver (if
38ad55ead7SLucas De Marchi  * any). The minor version is also checked and a notice emitted to the log if
39ad55ead7SLucas De Marchi  * the version found is smaller than the version wanted. This is done only for
40ad55ead7SLucas De Marchi  * informational purposes so users may have a chance to upgrade, but the driver
41ad55ead7SLucas De Marchi  * still loads and use the older firmware.
42ad55ead7SLucas De Marchi  *
43ad55ead7SLucas De Marchi  * Examples:
44ad55ead7SLucas De Marchi  *
45ad55ead7SLucas De Marchi  *	1) Platform officially supported by i915 - using Tigerlake as example.
46ad55ead7SLucas De Marchi  *	   Driver loads the following firmware blobs from disk:
47ad55ead7SLucas De Marchi  *
48ad55ead7SLucas De Marchi  *		- i915/tgl_guc_<major>.bin
49ad55ead7SLucas De Marchi  *		- i915/tgl_huc.bin
50ad55ead7SLucas De Marchi  *
51ad55ead7SLucas De Marchi  *	   <major> number for GuC is checked that it matches the version inside
52ad55ead7SLucas De Marchi  *	   the blob. <minor> version is checked and if smaller than the expected
53ad55ead7SLucas De Marchi  *	   an info message is emitted about that.
54ad55ead7SLucas De Marchi  *
55ad55ead7SLucas De Marchi  *	1) XE_<FUTUREINTELPLATFORM>, still under require_force_probe. Using
56ad55ead7SLucas De Marchi  *	   "wipplat" as a short-name. Driver loads the following firmware blobs
57ad55ead7SLucas De Marchi  *	   from disk:
58ad55ead7SLucas De Marchi  *
59ad55ead7SLucas De Marchi  *		- xe/wipplat_guc_<major>.<minor>.<patch>.bin
60ad55ead7SLucas De Marchi  *		- xe/wipplat_huc_<major>.<minor>.<patch>.bin
61ad55ead7SLucas De Marchi  *
62ad55ead7SLucas De Marchi  *	   <major> and <minor> are checked that they match the version inside
63ad55ead7SLucas De Marchi  *	   the blob. Both of them need to match exactly what the driver is
64ad55ead7SLucas De Marchi  *	   expecting, otherwise it fails.
65ad55ead7SLucas De Marchi  *
66ad55ead7SLucas De Marchi  *	3) Platform officially supported by xe and out of force-probe. Using
67ad55ead7SLucas De Marchi  *	   "plat" as a short-name. Except for the different directory, the
68ad55ead7SLucas De Marchi  *	   behavior is the same as (1). Driver loads the following firmware
69ad55ead7SLucas De Marchi  *	   blobs from disk:
70ad55ead7SLucas De Marchi  *
71ad55ead7SLucas De Marchi  *		- xe/plat_guc_<major>.bin
72ad55ead7SLucas De Marchi  *		- xe/plat_huc.bin
73ad55ead7SLucas De Marchi  *
74ad55ead7SLucas De Marchi  *	   <major> number for GuC is checked that it matches the version inside
75ad55ead7SLucas De Marchi  *	   the blob. <minor> version is checked and if smaller than the expected
76ad55ead7SLucas De Marchi  *	   an info message is emitted about that.
77ad55ead7SLucas De Marchi  *
78ad55ead7SLucas De Marchi  * For the platforms already released with a major version, they should never be
79ad55ead7SLucas De Marchi  * removed from the table. Instead new entries with newer versions may be added
80ad55ead7SLucas De Marchi  * before them, so they take precedence.
81ad55ead7SLucas De Marchi  *
82ad55ead7SLucas De Marchi  * TODO: Currently there's no fallback on major version. That's because xe
83ad55ead7SLucas De Marchi  * driver only supports the one major version of each firmware in the table.
84ad55ead7SLucas De Marchi  * This needs to be fixed when the major version of GuC is updated.
85ad55ead7SLucas De Marchi  */
86ad55ead7SLucas De Marchi 
87ad55ead7SLucas De Marchi struct uc_fw_entry {
88ad55ead7SLucas De Marchi 	enum xe_platform platform;
89ad55ead7SLucas De Marchi 	struct {
90ad55ead7SLucas De Marchi 		const char *path;
91ad55ead7SLucas De Marchi 		u16 major;
92ad55ead7SLucas De Marchi 		u16 minor;
93ad55ead7SLucas De Marchi 		bool full_ver_required;
94ad55ead7SLucas De Marchi 	};
95ad55ead7SLucas De Marchi };
96ad55ead7SLucas De Marchi 
97ad55ead7SLucas De Marchi struct fw_blobs_by_type {
98ad55ead7SLucas De Marchi 	const struct uc_fw_entry *entries;
99ad55ead7SLucas De Marchi 	u32 count;
100ad55ead7SLucas De Marchi };
101ad55ead7SLucas De Marchi 
102ad55ead7SLucas De Marchi #define XE_GUC_FIRMWARE_DEFS(fw_def, mmp_ver, major_ver)			\
103ad55ead7SLucas De Marchi 	fw_def(METEORLAKE,	mmp_ver(  i915,	guc,	mtl,	70, 6, 4))	\
104ad55ead7SLucas De Marchi 	fw_def(PVC,		mmp_ver(  xe,	guc,	pvc,	70, 6, 4))	\
105ad55ead7SLucas De Marchi 	fw_def(DG2,		major_ver(i915,	guc,	dg2,	70, 5))		\
106ad55ead7SLucas De Marchi 	fw_def(DG1,		major_ver(i915,	guc,	dg1,	70, 5))		\
107ad55ead7SLucas De Marchi 	fw_def(ALDERLAKE_P,	major_ver(i915,	guc,	adlp,	70, 5))		\
108ad55ead7SLucas De Marchi 	fw_def(ALDERLAKE_S,	major_ver(i915,	guc,	tgl,	70, 5))		\
109*94324e6bSAnusha Srivatsa 	fw_def(ROCKETLAKE,	major_ver(i915,	guc,	tgl,	70, 5))		\
110ad55ead7SLucas De Marchi 	fw_def(TIGERLAKE,	major_ver(i915,	guc,	tgl,	70, 5))
111ad55ead7SLucas De Marchi 
112ad55ead7SLucas De Marchi #define XE_HUC_FIRMWARE_DEFS(fw_def, mmp_ver, no_ver)				\
113ad55ead7SLucas De Marchi 	fw_def(ALDERLAKE_S,	no_ver(i915,	huc,	tgl))			\
114ad55ead7SLucas De Marchi 	fw_def(DG1,		no_ver(i915,	huc,	dg1))			\
115*94324e6bSAnusha Srivatsa 	fw_def(ROCKETLAKE,	no_ver(i915,	huc,	tgl))			\
116ad55ead7SLucas De Marchi 	fw_def(TIGERLAKE,	no_ver(i915,	huc,	tgl))
117ad55ead7SLucas De Marchi 
118ad55ead7SLucas De Marchi #define MAKE_FW_PATH(dir__, uc__, shortname__, version__)			\
119ad55ead7SLucas De Marchi 	__stringify(dir__) "/" __stringify(shortname__) "_" __stringify(uc__) version__ ".bin"
120ad55ead7SLucas De Marchi 
121ad55ead7SLucas De Marchi #define fw_filename_mmp_ver(dir_, uc_, shortname_, a, b, c)			\
122ad55ead7SLucas De Marchi 	MAKE_FW_PATH(dir_, uc_, shortname_, "_" __stringify(a ## . ## b ## . ## c))
123ad55ead7SLucas De Marchi #define fw_filename_major_ver(dir_, uc_, shortname_, a, b)			\
124ad55ead7SLucas De Marchi 	MAKE_FW_PATH(dir_, uc_, shortname_, "_" __stringify(a))
125ad55ead7SLucas De Marchi #define fw_filename_no_ver(dir_, uc_, shortname_)				\
126ad55ead7SLucas De Marchi 	MAKE_FW_PATH(dir_, uc_, shortname_, "")
127ad55ead7SLucas De Marchi 
128ad55ead7SLucas De Marchi #define uc_fw_entry_mmp_ver(dir_, uc_, shortname_, a, b, c)			\
129ad55ead7SLucas De Marchi 	{ fw_filename_mmp_ver(dir_, uc_, shortname_, a, b, c),			\
130ad55ead7SLucas De Marchi 	  a, b, true }
131ad55ead7SLucas De Marchi #define uc_fw_entry_major_ver(dir_, uc_, shortname_, a, b)			\
132ad55ead7SLucas De Marchi 	{ fw_filename_major_ver(dir_, uc_, shortname_, a, b),			\
133ad55ead7SLucas De Marchi 	  a, b }
134ad55ead7SLucas De Marchi #define uc_fw_entry_no_ver(dir_, uc_, shortname_)				\
135ad55ead7SLucas De Marchi 	{ fw_filename_no_ver(dir_, uc_, shortname_),				\
136ad55ead7SLucas De Marchi 	  0, 0 }
137ad55ead7SLucas De Marchi 
138ad55ead7SLucas De Marchi /* All blobs need to be declared via MODULE_FIRMWARE() */
139ad55ead7SLucas De Marchi #define XE_UC_MODULE_FIRMWARE(platform__, fw_filename)				\
140ad55ead7SLucas De Marchi 	MODULE_FIRMWARE(fw_filename);
141ad55ead7SLucas De Marchi 
142ad55ead7SLucas De Marchi #define XE_UC_FW_ENTRY(platform__, entry__)					\
143ad55ead7SLucas De Marchi 	{									\
144ad55ead7SLucas De Marchi 		.platform = XE_ ## platform__,					\
145ad55ead7SLucas De Marchi 		entry__,							\
146ad55ead7SLucas De Marchi 	},
147ad55ead7SLucas De Marchi 
148ad55ead7SLucas De Marchi XE_GUC_FIRMWARE_DEFS(XE_UC_MODULE_FIRMWARE,					\
149ad55ead7SLucas De Marchi 		     fw_filename_mmp_ver, fw_filename_major_ver)
150ad55ead7SLucas De Marchi XE_HUC_FIRMWARE_DEFS(XE_UC_MODULE_FIRMWARE,					\
151ad55ead7SLucas De Marchi 		     fw_filename_mmp_ver, fw_filename_no_ver)
152ad55ead7SLucas De Marchi 
153dd08ebf6SMatthew Brost static struct xe_gt *
154dd08ebf6SMatthew Brost __uc_fw_to_gt(struct xe_uc_fw *uc_fw, enum xe_uc_fw_type type)
155dd08ebf6SMatthew Brost {
156dd08ebf6SMatthew Brost 	if (type == XE_UC_FW_TYPE_GUC)
157dd08ebf6SMatthew Brost 		return container_of(uc_fw, struct xe_gt, uc.guc.fw);
158dd08ebf6SMatthew Brost 
159dd08ebf6SMatthew Brost 	XE_BUG_ON(type != XE_UC_FW_TYPE_HUC);
160dd08ebf6SMatthew Brost 	return container_of(uc_fw, struct xe_gt, uc.huc.fw);
161dd08ebf6SMatthew Brost }
162dd08ebf6SMatthew Brost 
163dd08ebf6SMatthew Brost static struct xe_gt *uc_fw_to_gt(struct xe_uc_fw *uc_fw)
164dd08ebf6SMatthew Brost {
165dd08ebf6SMatthew Brost 	return __uc_fw_to_gt(uc_fw, uc_fw->type);
166dd08ebf6SMatthew Brost }
167dd08ebf6SMatthew Brost 
168dd08ebf6SMatthew Brost static struct xe_device *uc_fw_to_xe(struct xe_uc_fw *uc_fw)
169dd08ebf6SMatthew Brost {
170dd08ebf6SMatthew Brost 	return gt_to_xe(uc_fw_to_gt(uc_fw));
171dd08ebf6SMatthew Brost }
172dd08ebf6SMatthew Brost 
173dd08ebf6SMatthew Brost static void
174dd08ebf6SMatthew Brost uc_fw_auto_select(struct xe_device *xe, struct xe_uc_fw *uc_fw)
175dd08ebf6SMatthew Brost {
176ad55ead7SLucas De Marchi 	static const struct uc_fw_entry entries_guc[] = {
177ad55ead7SLucas De Marchi 		XE_GUC_FIRMWARE_DEFS(XE_UC_FW_ENTRY,
178ad55ead7SLucas De Marchi 				     uc_fw_entry_mmp_ver,
179ad55ead7SLucas De Marchi 				     uc_fw_entry_major_ver)
180dd08ebf6SMatthew Brost 	};
181ad55ead7SLucas De Marchi 	static const struct uc_fw_entry entries_huc[] = {
182ad55ead7SLucas De Marchi 		XE_HUC_FIRMWARE_DEFS(XE_UC_FW_ENTRY,
183ad55ead7SLucas De Marchi 				     uc_fw_entry_mmp_ver,
184ad55ead7SLucas De Marchi 				     uc_fw_entry_no_ver)
185dd08ebf6SMatthew Brost 	};
186dd08ebf6SMatthew Brost 	static const struct fw_blobs_by_type blobs_all[XE_UC_FW_NUM_TYPES] = {
187ad55ead7SLucas De Marchi 		[XE_UC_FW_TYPE_GUC] = { entries_guc, ARRAY_SIZE(entries_guc) },
188ad55ead7SLucas De Marchi 		[XE_UC_FW_TYPE_HUC] = { entries_huc, ARRAY_SIZE(entries_huc) },
189dd08ebf6SMatthew Brost 	};
190ad55ead7SLucas De Marchi 	static const struct uc_fw_entry *entries;
191dd08ebf6SMatthew Brost 	enum xe_platform p = xe->info.platform;
192ad55ead7SLucas De Marchi 	u32 count;
193dd08ebf6SMatthew Brost 	int i;
194dd08ebf6SMatthew Brost 
195dd08ebf6SMatthew Brost 	XE_BUG_ON(uc_fw->type >= ARRAY_SIZE(blobs_all));
196ad55ead7SLucas De Marchi 	entries = blobs_all[uc_fw->type].entries;
197ad55ead7SLucas De Marchi 	count = blobs_all[uc_fw->type].count;
198dd08ebf6SMatthew Brost 
199ad55ead7SLucas De Marchi 	for (i = 0; i < count && p <= entries[i].platform; i++) {
200ad55ead7SLucas De Marchi 		if (p == entries[i].platform) {
201ad55ead7SLucas De Marchi 			uc_fw->path = entries[i].path;
202ad55ead7SLucas De Marchi 			uc_fw->major_ver_wanted = entries[i].major;
203ad55ead7SLucas De Marchi 			uc_fw->minor_ver_wanted = entries[i].minor;
204ad55ead7SLucas De Marchi 			uc_fw->full_ver_required = entries[i].full_ver_required;
205dd08ebf6SMatthew Brost 			break;
206dd08ebf6SMatthew Brost 		}
207dd08ebf6SMatthew Brost 	}
208dd08ebf6SMatthew Brost }
209dd08ebf6SMatthew Brost 
210dd08ebf6SMatthew Brost /**
211dd08ebf6SMatthew Brost  * xe_uc_fw_copy_rsa - copy fw RSA to buffer
212dd08ebf6SMatthew Brost  *
213dd08ebf6SMatthew Brost  * @uc_fw: uC firmware
214dd08ebf6SMatthew Brost  * @dst: dst buffer
215dd08ebf6SMatthew Brost  * @max_len: max number of bytes to copy
216dd08ebf6SMatthew Brost  *
217dd08ebf6SMatthew Brost  * Return: number of copied bytes.
218dd08ebf6SMatthew Brost  */
219dd08ebf6SMatthew Brost size_t xe_uc_fw_copy_rsa(struct xe_uc_fw *uc_fw, void *dst, u32 max_len)
220dd08ebf6SMatthew Brost {
221dd08ebf6SMatthew Brost 	struct xe_device *xe = uc_fw_to_xe(uc_fw);
222dd08ebf6SMatthew Brost 	u32 size = min_t(u32, uc_fw->rsa_size, max_len);
223dd08ebf6SMatthew Brost 
224dd08ebf6SMatthew Brost 	XE_BUG_ON(size % 4);
225dd08ebf6SMatthew Brost 	XE_BUG_ON(!xe_uc_fw_is_available(uc_fw));
226dd08ebf6SMatthew Brost 
227dd08ebf6SMatthew Brost 	xe_map_memcpy_from(xe, dst, &uc_fw->bo->vmap,
228dd08ebf6SMatthew Brost 			   xe_uc_fw_rsa_offset(uc_fw), size);
229dd08ebf6SMatthew Brost 
230dd08ebf6SMatthew Brost 	return size;
231dd08ebf6SMatthew Brost }
232dd08ebf6SMatthew Brost 
233dd08ebf6SMatthew Brost static void uc_fw_fini(struct drm_device *drm, void *arg)
234dd08ebf6SMatthew Brost {
235dd08ebf6SMatthew Brost 	struct xe_uc_fw *uc_fw = arg;
236dd08ebf6SMatthew Brost 
237dd08ebf6SMatthew Brost 	if (!xe_uc_fw_is_available(uc_fw))
238dd08ebf6SMatthew Brost 		return;
239dd08ebf6SMatthew Brost 
240dd08ebf6SMatthew Brost 	xe_bo_unpin_map_no_vm(uc_fw->bo);
241dd08ebf6SMatthew Brost 	xe_uc_fw_change_status(uc_fw, XE_UC_FIRMWARE_SELECTED);
242dd08ebf6SMatthew Brost }
243dd08ebf6SMatthew Brost 
24499c821b0SMatthew Brost static void guc_read_css_info(struct xe_uc_fw *uc_fw, struct uc_css_header *css)
24599c821b0SMatthew Brost {
24699c821b0SMatthew Brost 	struct xe_gt *gt = uc_fw_to_gt(uc_fw);
24799c821b0SMatthew Brost 	struct xe_guc *guc = &gt->uc.guc;
24899c821b0SMatthew Brost 
24999c821b0SMatthew Brost 	XE_BUG_ON(uc_fw->type != XE_UC_FW_TYPE_GUC);
25099c821b0SMatthew Brost 	XE_WARN_ON(uc_fw->major_ver_found < 70);
25199c821b0SMatthew Brost 
25299c821b0SMatthew Brost 	if (uc_fw->major_ver_found > 70 || uc_fw->minor_ver_found >= 6) {
25399c821b0SMatthew Brost 		/* v70.6.0 adds CSS header support */
25499c821b0SMatthew Brost 		guc->submission_state.version.major =
25599c821b0SMatthew Brost 			FIELD_GET(CSS_SW_VERSION_UC_MAJOR,
25699c821b0SMatthew Brost 				  css->submission_version);
25799c821b0SMatthew Brost 		guc->submission_state.version.minor =
25899c821b0SMatthew Brost 			FIELD_GET(CSS_SW_VERSION_UC_MINOR,
25999c821b0SMatthew Brost 				  css->submission_version);
26099c821b0SMatthew Brost 		guc->submission_state.version.patch =
26199c821b0SMatthew Brost 			FIELD_GET(CSS_SW_VERSION_UC_PATCH,
26299c821b0SMatthew Brost 				  css->submission_version);
26399c821b0SMatthew Brost 	} else if (uc_fw->minor_ver_found >= 3) {
26499c821b0SMatthew Brost 		/* v70.3.0 introduced v1.1.0 */
26599c821b0SMatthew Brost 		guc->submission_state.version.major = 1;
26699c821b0SMatthew Brost 		guc->submission_state.version.minor = 1;
26799c821b0SMatthew Brost 		guc->submission_state.version.patch = 0;
26899c821b0SMatthew Brost 	} else {
26999c821b0SMatthew Brost 		/* v70.0.0 introduced v1.0.0 */
27099c821b0SMatthew Brost 		guc->submission_state.version.major = 1;
27199c821b0SMatthew Brost 		guc->submission_state.version.minor = 0;
27299c821b0SMatthew Brost 		guc->submission_state.version.patch = 0;
27399c821b0SMatthew Brost 	}
27499c821b0SMatthew Brost 
27599c821b0SMatthew Brost 	uc_fw->private_data_size = css->private_data_size;
27699c821b0SMatthew Brost }
27799c821b0SMatthew Brost 
278ad55ead7SLucas De Marchi static int uc_fw_check_version_requirements(struct xe_uc_fw *uc_fw)
279ad55ead7SLucas De Marchi {
280ad55ead7SLucas De Marchi 	struct xe_device *xe = uc_fw_to_xe(uc_fw);
281ad55ead7SLucas De Marchi 
282ad55ead7SLucas De Marchi 	/* Driver has no requirement on any version, any is good. */
283ad55ead7SLucas De Marchi 	if (!uc_fw->major_ver_wanted)
284ad55ead7SLucas De Marchi 		return 0;
285ad55ead7SLucas De Marchi 
286ad55ead7SLucas De Marchi 	/*
287ad55ead7SLucas De Marchi 	 * If full version is required, both major and minor should match.
288ad55ead7SLucas De Marchi 	 * Otherwise, at least the major version.
289ad55ead7SLucas De Marchi 	 */
290ad55ead7SLucas De Marchi 	if (uc_fw->major_ver_wanted != uc_fw->major_ver_found ||
291ad55ead7SLucas De Marchi 	    (uc_fw->full_ver_required &&
292ad55ead7SLucas De Marchi 	     uc_fw->minor_ver_wanted != uc_fw->minor_ver_found)) {
293ad55ead7SLucas De Marchi 		drm_notice(&xe->drm, "%s firmware %s: unexpected version: %u.%u != %u.%u\n",
294ad55ead7SLucas De Marchi 			   xe_uc_fw_type_repr(uc_fw->type), uc_fw->path,
295ad55ead7SLucas De Marchi 			   uc_fw->major_ver_found, uc_fw->minor_ver_found,
296ad55ead7SLucas De Marchi 			   uc_fw->major_ver_wanted, uc_fw->minor_ver_wanted);
297ad55ead7SLucas De Marchi 		goto fail;
298ad55ead7SLucas De Marchi 	}
299ad55ead7SLucas De Marchi 
300ad55ead7SLucas De Marchi 	if (uc_fw->minor_ver_wanted > uc_fw->minor_ver_found) {
301ad55ead7SLucas De Marchi 		drm_notice(&xe->drm, "%s firmware (%u.%u) is recommended, but only (%u.%u) was found in %s\n",
302ad55ead7SLucas De Marchi 			   xe_uc_fw_type_repr(uc_fw->type),
303ad55ead7SLucas De Marchi 			   uc_fw->major_ver_wanted, uc_fw->minor_ver_wanted,
304ad55ead7SLucas De Marchi 			   uc_fw->major_ver_found, uc_fw->minor_ver_found,
305ad55ead7SLucas De Marchi 			   uc_fw->path);
306ad55ead7SLucas De Marchi 		drm_info(&xe->drm, "Consider updating your linux-firmware pkg or downloading from %s\n",
307ad55ead7SLucas De Marchi 			 XE_UC_FIRMWARE_URL);
308ad55ead7SLucas De Marchi 	}
309ad55ead7SLucas De Marchi 
310ad55ead7SLucas De Marchi 	return 0;
311ad55ead7SLucas De Marchi 
312ad55ead7SLucas De Marchi fail:
313ad55ead7SLucas De Marchi 	if (xe_uc_fw_is_overridden(uc_fw))
314ad55ead7SLucas De Marchi 		return 0;
315ad55ead7SLucas De Marchi 
316ad55ead7SLucas De Marchi 	return -ENOEXEC;
317ad55ead7SLucas De Marchi }
318ad55ead7SLucas De Marchi 
319dd08ebf6SMatthew Brost int xe_uc_fw_init(struct xe_uc_fw *uc_fw)
320dd08ebf6SMatthew Brost {
321dd08ebf6SMatthew Brost 	struct xe_device *xe = uc_fw_to_xe(uc_fw);
322dd08ebf6SMatthew Brost 	struct xe_gt *gt = uc_fw_to_gt(uc_fw);
323dd08ebf6SMatthew Brost 	struct device *dev = xe->drm.dev;
324dd08ebf6SMatthew Brost 	const struct firmware *fw = NULL;
325dd08ebf6SMatthew Brost 	struct uc_css_header *css;
326dd08ebf6SMatthew Brost 	struct xe_bo *obj;
327dd08ebf6SMatthew Brost 	size_t size;
328dd08ebf6SMatthew Brost 	int err;
329dd08ebf6SMatthew Brost 
330dd08ebf6SMatthew Brost 	/*
331dd08ebf6SMatthew Brost 	 * we use FIRMWARE_UNINITIALIZED to detect checks against uc_fw->status
332dd08ebf6SMatthew Brost 	 * before we're looked at the HW caps to see if we have uc support
333dd08ebf6SMatthew Brost 	 */
334dd08ebf6SMatthew Brost 	BUILD_BUG_ON(XE_UC_FIRMWARE_UNINITIALIZED);
335dd08ebf6SMatthew Brost 	XE_BUG_ON(uc_fw->status);
336dd08ebf6SMatthew Brost 	XE_BUG_ON(uc_fw->path);
337dd08ebf6SMatthew Brost 
338dd08ebf6SMatthew Brost 	uc_fw_auto_select(xe, uc_fw);
339dd08ebf6SMatthew Brost 	xe_uc_fw_change_status(uc_fw, uc_fw->path ? *uc_fw->path ?
340dd08ebf6SMatthew Brost 			       XE_UC_FIRMWARE_SELECTED :
341dd08ebf6SMatthew Brost 			       XE_UC_FIRMWARE_DISABLED :
342dd08ebf6SMatthew Brost 			       XE_UC_FIRMWARE_NOT_SUPPORTED);
343dd08ebf6SMatthew Brost 
344dd08ebf6SMatthew Brost 	/* Transform no huc in the list into firmware disabled */
345dd08ebf6SMatthew Brost 	if (uc_fw->type == XE_UC_FW_TYPE_HUC && !xe_uc_fw_is_supported(uc_fw)) {
346dd08ebf6SMatthew Brost 		xe_uc_fw_change_status(uc_fw, XE_UC_FIRMWARE_DISABLED);
347dd08ebf6SMatthew Brost 		err = -ENOPKG;
348dd08ebf6SMatthew Brost 		return err;
349dd08ebf6SMatthew Brost 	}
350dd08ebf6SMatthew Brost 	err = request_firmware(&fw, uc_fw->path, dev);
351dd08ebf6SMatthew Brost 	if (err)
352dd08ebf6SMatthew Brost 		goto fail;
353dd08ebf6SMatthew Brost 
354dd08ebf6SMatthew Brost 	/* Check the size of the blob before examining buffer contents */
355dd08ebf6SMatthew Brost 	if (unlikely(fw->size < sizeof(struct uc_css_header))) {
356dd08ebf6SMatthew Brost 		drm_warn(&xe->drm, "%s firmware %s: invalid size: %zu < %zu\n",
357dd08ebf6SMatthew Brost 			 xe_uc_fw_type_repr(uc_fw->type), uc_fw->path,
358dd08ebf6SMatthew Brost 			 fw->size, sizeof(struct uc_css_header));
359dd08ebf6SMatthew Brost 		err = -ENODATA;
360dd08ebf6SMatthew Brost 		goto fail;
361dd08ebf6SMatthew Brost 	}
362dd08ebf6SMatthew Brost 
363dd08ebf6SMatthew Brost 	css = (struct uc_css_header *)fw->data;
364dd08ebf6SMatthew Brost 
365dd08ebf6SMatthew Brost 	/* Check integrity of size values inside CSS header */
366dd08ebf6SMatthew Brost 	size = (css->header_size_dw - css->key_size_dw - css->modulus_size_dw -
367dd08ebf6SMatthew Brost 		css->exponent_size_dw) * sizeof(u32);
368dd08ebf6SMatthew Brost 	if (unlikely(size != sizeof(struct uc_css_header))) {
369dd08ebf6SMatthew Brost 		drm_warn(&xe->drm,
370dd08ebf6SMatthew Brost 			 "%s firmware %s: unexpected header size: %zu != %zu\n",
371dd08ebf6SMatthew Brost 			 xe_uc_fw_type_repr(uc_fw->type), uc_fw->path,
372dd08ebf6SMatthew Brost 			 fw->size, sizeof(struct uc_css_header));
373dd08ebf6SMatthew Brost 		err = -EPROTO;
374dd08ebf6SMatthew Brost 		goto fail;
375dd08ebf6SMatthew Brost 	}
376dd08ebf6SMatthew Brost 
377dd08ebf6SMatthew Brost 	/* uCode size must calculated from other sizes */
378dd08ebf6SMatthew Brost 	uc_fw->ucode_size = (css->size_dw - css->header_size_dw) * sizeof(u32);
379dd08ebf6SMatthew Brost 
380dd08ebf6SMatthew Brost 	/* now RSA */
381dd08ebf6SMatthew Brost 	uc_fw->rsa_size = css->key_size_dw * sizeof(u32);
382dd08ebf6SMatthew Brost 
383dd08ebf6SMatthew Brost 	/* At least, it should have header, uCode and RSA. Size of all three. */
384dd08ebf6SMatthew Brost 	size = sizeof(struct uc_css_header) + uc_fw->ucode_size +
385dd08ebf6SMatthew Brost 		uc_fw->rsa_size;
386dd08ebf6SMatthew Brost 	if (unlikely(fw->size < size)) {
387dd08ebf6SMatthew Brost 		drm_warn(&xe->drm, "%s firmware %s: invalid size: %zu < %zu\n",
388dd08ebf6SMatthew Brost 			 xe_uc_fw_type_repr(uc_fw->type), uc_fw->path,
389dd08ebf6SMatthew Brost 			 fw->size, size);
390dd08ebf6SMatthew Brost 		err = -ENOEXEC;
391dd08ebf6SMatthew Brost 		goto fail;
392dd08ebf6SMatthew Brost 	}
393dd08ebf6SMatthew Brost 
394dd08ebf6SMatthew Brost 	/* Get version numbers from the CSS header */
395dd08ebf6SMatthew Brost 	uc_fw->major_ver_found = FIELD_GET(CSS_SW_VERSION_UC_MAJOR,
396dd08ebf6SMatthew Brost 					   css->sw_version);
397dd08ebf6SMatthew Brost 	uc_fw->minor_ver_found = FIELD_GET(CSS_SW_VERSION_UC_MINOR,
398dd08ebf6SMatthew Brost 					   css->sw_version);
399dd08ebf6SMatthew Brost 
40061e72e77SLucas De Marchi 	drm_info(&xe->drm, "Using %s firmware (%u.%u) from %s\n",
40161e72e77SLucas De Marchi 		 xe_uc_fw_type_repr(uc_fw->type),
40261e72e77SLucas De Marchi 		 uc_fw->major_ver_found, uc_fw->minor_ver_found,
40361e72e77SLucas De Marchi 		 uc_fw->path);
40461e72e77SLucas De Marchi 
405ad55ead7SLucas De Marchi 	err = uc_fw_check_version_requirements(uc_fw);
406ad55ead7SLucas De Marchi 	if (err)
407dd08ebf6SMatthew Brost 		goto fail;
408dd08ebf6SMatthew Brost 
409dd08ebf6SMatthew Brost 	if (uc_fw->type == XE_UC_FW_TYPE_GUC)
41099c821b0SMatthew Brost 		guc_read_css_info(uc_fw, css);
411dd08ebf6SMatthew Brost 
412dd08ebf6SMatthew Brost 	obj = xe_bo_create_from_data(xe, gt, fw->data, fw->size,
413dd08ebf6SMatthew Brost 				     ttm_bo_type_kernel,
414dd08ebf6SMatthew Brost 				     XE_BO_CREATE_VRAM_IF_DGFX(gt) |
415dd08ebf6SMatthew Brost 				     XE_BO_CREATE_GGTT_BIT);
416dd08ebf6SMatthew Brost 	if (IS_ERR(obj)) {
417dd08ebf6SMatthew Brost 		drm_notice(&xe->drm, "%s firmware %s: failed to create / populate bo",
418dd08ebf6SMatthew Brost 			   xe_uc_fw_type_repr(uc_fw->type), uc_fw->path);
419dd08ebf6SMatthew Brost 		err = PTR_ERR(obj);
420dd08ebf6SMatthew Brost 		goto fail;
421dd08ebf6SMatthew Brost 	}
422dd08ebf6SMatthew Brost 
423dd08ebf6SMatthew Brost 	uc_fw->bo = obj;
424dd08ebf6SMatthew Brost 	uc_fw->size = fw->size;
425dd08ebf6SMatthew Brost 	xe_uc_fw_change_status(uc_fw, XE_UC_FIRMWARE_AVAILABLE);
426dd08ebf6SMatthew Brost 
427dd08ebf6SMatthew Brost 	release_firmware(fw);
428dd08ebf6SMatthew Brost 
429dd08ebf6SMatthew Brost 	err = drmm_add_action_or_reset(&xe->drm, uc_fw_fini, uc_fw);
430dd08ebf6SMatthew Brost 	if (err)
431dd08ebf6SMatthew Brost 		return err;
432dd08ebf6SMatthew Brost 
433dd08ebf6SMatthew Brost 	return 0;
434dd08ebf6SMatthew Brost 
435dd08ebf6SMatthew Brost fail:
436dd08ebf6SMatthew Brost 	xe_uc_fw_change_status(uc_fw, err == -ENOENT ?
437dd08ebf6SMatthew Brost 			       XE_UC_FIRMWARE_MISSING :
438dd08ebf6SMatthew Brost 			       XE_UC_FIRMWARE_ERROR);
439dd08ebf6SMatthew Brost 
440dd08ebf6SMatthew Brost 	drm_notice(&xe->drm, "%s firmware %s: fetch failed with error %d\n",
441dd08ebf6SMatthew Brost 		   xe_uc_fw_type_repr(uc_fw->type), uc_fw->path, err);
442dd08ebf6SMatthew Brost 	drm_info(&xe->drm, "%s firmware(s) can be downloaded from %s\n",
443dd08ebf6SMatthew Brost 		 xe_uc_fw_type_repr(uc_fw->type), XE_UC_FIRMWARE_URL);
444dd08ebf6SMatthew Brost 
445dd08ebf6SMatthew Brost 	release_firmware(fw);		/* OK even if fw is NULL */
446dd08ebf6SMatthew Brost 	return err;
447dd08ebf6SMatthew Brost }
448dd08ebf6SMatthew Brost 
449dd08ebf6SMatthew Brost static u32 uc_fw_ggtt_offset(struct xe_uc_fw *uc_fw)
450dd08ebf6SMatthew Brost {
451dd08ebf6SMatthew Brost 	return xe_bo_ggtt_addr(uc_fw->bo);
452dd08ebf6SMatthew Brost }
453dd08ebf6SMatthew Brost 
454dd08ebf6SMatthew Brost static int uc_fw_xfer(struct xe_uc_fw *uc_fw, u32 offset, u32 dma_flags)
455dd08ebf6SMatthew Brost {
456dd08ebf6SMatthew Brost 	struct xe_device *xe = uc_fw_to_xe(uc_fw);
457dd08ebf6SMatthew Brost 	struct xe_gt *gt = uc_fw_to_gt(uc_fw);
4587aaec3a6SRodrigo Vivi 	u32 src_offset, dma_ctrl;
459dd08ebf6SMatthew Brost 	int ret;
460dd08ebf6SMatthew Brost 
461dd08ebf6SMatthew Brost 	xe_force_wake_assert_held(gt_to_fw(gt), XE_FW_GT);
462dd08ebf6SMatthew Brost 
463dd08ebf6SMatthew Brost 	/* Set the source address for the uCode */
464dd08ebf6SMatthew Brost 	src_offset = uc_fw_ggtt_offset(uc_fw);
465dd08ebf6SMatthew Brost 	xe_mmio_write32(gt, DMA_ADDR_0_LOW.reg, lower_32_bits(src_offset));
466dd08ebf6SMatthew Brost 	xe_mmio_write32(gt, DMA_ADDR_0_HIGH.reg, upper_32_bits(src_offset));
467dd08ebf6SMatthew Brost 
468dd08ebf6SMatthew Brost 	/* Set the DMA destination */
469dd08ebf6SMatthew Brost 	xe_mmio_write32(gt, DMA_ADDR_1_LOW.reg, offset);
470dd08ebf6SMatthew Brost 	xe_mmio_write32(gt, DMA_ADDR_1_HIGH.reg, DMA_ADDRESS_SPACE_WOPCM);
471dd08ebf6SMatthew Brost 
472dd08ebf6SMatthew Brost 	/*
473dd08ebf6SMatthew Brost 	 * Set the transfer size. The header plus uCode will be copied to WOPCM
474dd08ebf6SMatthew Brost 	 * via DMA, excluding any other components
475dd08ebf6SMatthew Brost 	 */
476dd08ebf6SMatthew Brost 	xe_mmio_write32(gt, DMA_COPY_SIZE.reg,
477dd08ebf6SMatthew Brost 			sizeof(struct uc_css_header) + uc_fw->ucode_size);
478dd08ebf6SMatthew Brost 
479dd08ebf6SMatthew Brost 	/* Start the DMA */
480dd08ebf6SMatthew Brost 	xe_mmio_write32(gt, DMA_CTRL.reg,
481dd08ebf6SMatthew Brost 			_MASKED_BIT_ENABLE(dma_flags | START_DMA));
482dd08ebf6SMatthew Brost 
483dd08ebf6SMatthew Brost 	/* Wait for DMA to finish */
4847dc9b92dSRodrigo Vivi 	ret = xe_mmio_wait32(gt, DMA_CTRL.reg, 0, START_DMA, 100000, &dma_ctrl,
4857dc9b92dSRodrigo Vivi 			     false);
486dd08ebf6SMatthew Brost 	if (ret)
487dd08ebf6SMatthew Brost 		drm_err(&xe->drm, "DMA for %s fw failed, DMA_CTRL=%u\n",
4887aaec3a6SRodrigo Vivi 			xe_uc_fw_type_repr(uc_fw->type), dma_ctrl);
489dd08ebf6SMatthew Brost 
490dd08ebf6SMatthew Brost 	/* Disable the bits once DMA is over */
491dd08ebf6SMatthew Brost 	xe_mmio_write32(gt, DMA_CTRL.reg, _MASKED_BIT_DISABLE(dma_flags));
492dd08ebf6SMatthew Brost 
493dd08ebf6SMatthew Brost 	return ret;
494dd08ebf6SMatthew Brost }
495dd08ebf6SMatthew Brost 
496dd08ebf6SMatthew Brost int xe_uc_fw_upload(struct xe_uc_fw *uc_fw, u32 offset, u32 dma_flags)
497dd08ebf6SMatthew Brost {
498dd08ebf6SMatthew Brost 	struct xe_device *xe = uc_fw_to_xe(uc_fw);
499dd08ebf6SMatthew Brost 	int err;
500dd08ebf6SMatthew Brost 
501dd08ebf6SMatthew Brost 	/* make sure the status was cleared the last time we reset the uc */
502dd08ebf6SMatthew Brost 	XE_BUG_ON(xe_uc_fw_is_loaded(uc_fw));
503dd08ebf6SMatthew Brost 
504dd08ebf6SMatthew Brost 	if (!xe_uc_fw_is_loadable(uc_fw))
505dd08ebf6SMatthew Brost 		return -ENOEXEC;
506dd08ebf6SMatthew Brost 
507dd08ebf6SMatthew Brost 	/* Call custom loader */
508dd08ebf6SMatthew Brost 	err = uc_fw_xfer(uc_fw, offset, dma_flags);
509dd08ebf6SMatthew Brost 	if (err)
510dd08ebf6SMatthew Brost 		goto fail;
511dd08ebf6SMatthew Brost 
512dd08ebf6SMatthew Brost 	xe_uc_fw_change_status(uc_fw, XE_UC_FIRMWARE_TRANSFERRED);
513dd08ebf6SMatthew Brost 	return 0;
514dd08ebf6SMatthew Brost 
515dd08ebf6SMatthew Brost fail:
516dd08ebf6SMatthew Brost 	drm_err(&xe->drm, "Failed to load %s firmware %s (%d)\n",
517dd08ebf6SMatthew Brost 		xe_uc_fw_type_repr(uc_fw->type), uc_fw->path,
518dd08ebf6SMatthew Brost 		err);
519dd08ebf6SMatthew Brost 	xe_uc_fw_change_status(uc_fw, XE_UC_FIRMWARE_LOAD_FAIL);
520dd08ebf6SMatthew Brost 	return err;
521dd08ebf6SMatthew Brost }
522dd08ebf6SMatthew Brost 
523dd08ebf6SMatthew Brost 
524dd08ebf6SMatthew Brost void xe_uc_fw_print(struct xe_uc_fw *uc_fw, struct drm_printer *p)
525dd08ebf6SMatthew Brost {
526dd08ebf6SMatthew Brost 	drm_printf(p, "%s firmware: %s\n",
527dd08ebf6SMatthew Brost 		   xe_uc_fw_type_repr(uc_fw->type), uc_fw->path);
528dd08ebf6SMatthew Brost 	drm_printf(p, "\tstatus: %s\n",
529dd08ebf6SMatthew Brost 		   xe_uc_fw_status_repr(uc_fw->status));
530dd08ebf6SMatthew Brost 	drm_printf(p, "\tversion: wanted %u.%u, found %u.%u\n",
531dd08ebf6SMatthew Brost 		   uc_fw->major_ver_wanted, uc_fw->minor_ver_wanted,
532dd08ebf6SMatthew Brost 		   uc_fw->major_ver_found, uc_fw->minor_ver_found);
533dd08ebf6SMatthew Brost 	drm_printf(p, "\tuCode: %u bytes\n", uc_fw->ucode_size);
534dd08ebf6SMatthew Brost 	drm_printf(p, "\tRSA: %u bytes\n", uc_fw->rsa_size);
53599c821b0SMatthew Brost 
53699c821b0SMatthew Brost 	if (uc_fw->type == XE_UC_FW_TYPE_GUC) {
53799c821b0SMatthew Brost 		struct xe_gt *gt = uc_fw_to_gt(uc_fw);
53899c821b0SMatthew Brost 		struct xe_guc *guc = &gt->uc.guc;
53999c821b0SMatthew Brost 
54099c821b0SMatthew Brost 		drm_printf(p, "\tSubmit version: %u.%u.%u\n",
54199c821b0SMatthew Brost 			   guc->submission_state.version.major,
54299c821b0SMatthew Brost 			   guc->submission_state.version.minor,
54399c821b0SMatthew Brost 			   guc->submission_state.version.patch);
54499c821b0SMatthew Brost 	}
545dd08ebf6SMatthew Brost }
546