2 * Copyright © 2016-2017 Intel Corporation
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:
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
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
25 #include <linux/firmware.h>
26 #include <drm/drm_print.h>
28 #include "intel_uc_fw.h"
32 * intel_uc_fw_fetch - fetch uC firmware
34 * @dev_priv: device private
37 * Fetch uC firmware into GEM obj.
39 void intel_uc_fw_fetch(struct drm_i915_private
*dev_priv
,
40 struct intel_uc_fw
*uc_fw
)
42 struct pci_dev
*pdev
= dev_priv
->drm
.pdev
;
43 struct drm_i915_gem_object
*obj
;
44 const struct firmware
*fw
= NULL
;
45 struct uc_css_header
*css
;
49 DRM_DEBUG_DRIVER("%s fw fetch %s\n",
50 intel_uc_fw_type_repr(uc_fw
->type
), uc_fw
->path
);
55 uc_fw
->fetch_status
= INTEL_UC_FIRMWARE_PENDING
;
56 DRM_DEBUG_DRIVER("%s fw fetch %s\n",
57 intel_uc_fw_type_repr(uc_fw
->type
),
58 intel_uc_fw_status_repr(uc_fw
->fetch_status
));
60 err
= request_firmware(&fw
, uc_fw
->path
, &pdev
->dev
);
62 DRM_DEBUG_DRIVER("%s fw request_firmware err=%d\n",
63 intel_uc_fw_type_repr(uc_fw
->type
), err
);
67 DRM_DEBUG_DRIVER("%s fw size %zu ptr %p\n",
68 intel_uc_fw_type_repr(uc_fw
->type
), fw
->size
, fw
);
70 /* Check the size of the blob before examining buffer contents */
71 if (fw
->size
< sizeof(struct uc_css_header
)) {
72 DRM_WARN("%s: Unexpected firmware size (%zu, min %zu)\n",
73 intel_uc_fw_type_repr(uc_fw
->type
),
74 fw
->size
, sizeof(struct uc_css_header
));
79 css
= (struct uc_css_header
*)fw
->data
;
81 /* Firmware bits always start from header */
82 uc_fw
->header_offset
= 0;
83 uc_fw
->header_size
= (css
->header_size_dw
- css
->modulus_size_dw
-
84 css
->key_size_dw
- css
->exponent_size_dw
) *
87 if (uc_fw
->header_size
!= sizeof(struct uc_css_header
)) {
88 DRM_WARN("%s: Mismatched firmware header definition\n",
89 intel_uc_fw_type_repr(uc_fw
->type
));
95 uc_fw
->ucode_offset
= uc_fw
->header_offset
+ uc_fw
->header_size
;
96 uc_fw
->ucode_size
= (css
->size_dw
- css
->header_size_dw
) * sizeof(u32
);
98 /* Header and uCode will be loaded to WOPCM */
99 size
= uc_fw
->header_size
+ uc_fw
->ucode_size
;
100 if (size
> intel_guc_wopcm_size(dev_priv
)) {
101 DRM_WARN("%s: Firmware is too large to fit in WOPCM\n",
102 intel_uc_fw_type_repr(uc_fw
->type
));
108 if (css
->key_size_dw
!= UOS_RSA_SCRATCH_COUNT
) {
109 DRM_WARN("%s: Mismatched firmware RSA key size (%u)\n",
110 intel_uc_fw_type_repr(uc_fw
->type
), css
->key_size_dw
);
114 uc_fw
->rsa_offset
= uc_fw
->ucode_offset
+ uc_fw
->ucode_size
;
115 uc_fw
->rsa_size
= css
->key_size_dw
* sizeof(u32
);
117 /* At least, it should have header, uCode and RSA. Size of all three. */
118 size
= uc_fw
->header_size
+ uc_fw
->ucode_size
+ uc_fw
->rsa_size
;
119 if (fw
->size
< size
) {
120 DRM_WARN("%s: Truncated firmware (%zu, expected %zu)\n",
121 intel_uc_fw_type_repr(uc_fw
->type
), fw
->size
, size
);
127 * The GuC firmware image has the version number embedded at a
128 * well-known offset within the firmware blob; note that major / minor
129 * version are TWO bytes each (i.e. u16), although all pointers and
130 * offsets are defined in terms of bytes (u8).
132 switch (uc_fw
->type
) {
133 case INTEL_UC_FW_TYPE_GUC
:
134 uc_fw
->major_ver_found
= css
->guc
.sw_version
>> 16;
135 uc_fw
->minor_ver_found
= css
->guc
.sw_version
& 0xFFFF;
138 case INTEL_UC_FW_TYPE_HUC
:
139 uc_fw
->major_ver_found
= css
->huc
.sw_version
>> 16;
140 uc_fw
->minor_ver_found
= css
->huc
.sw_version
& 0xFFFF;
144 MISSING_CASE(uc_fw
->type
);
148 DRM_DEBUG_DRIVER("%s fw version %u.%u (wanted %u.%u)\n",
149 intel_uc_fw_type_repr(uc_fw
->type
),
150 uc_fw
->major_ver_found
, uc_fw
->minor_ver_found
,
151 uc_fw
->major_ver_wanted
, uc_fw
->minor_ver_wanted
);
153 if (uc_fw
->major_ver_wanted
== 0 && uc_fw
->minor_ver_wanted
== 0) {
154 DRM_NOTE("%s: Skipping firmware version check\n",
155 intel_uc_fw_type_repr(uc_fw
->type
));
156 } else if (uc_fw
->major_ver_found
!= uc_fw
->major_ver_wanted
||
157 uc_fw
->minor_ver_found
< uc_fw
->minor_ver_wanted
) {
158 DRM_NOTE("%s: Wrong firmware version (%u.%u, required %u.%u)\n",
159 intel_uc_fw_type_repr(uc_fw
->type
),
160 uc_fw
->major_ver_found
, uc_fw
->minor_ver_found
,
161 uc_fw
->major_ver_wanted
, uc_fw
->minor_ver_wanted
);
166 obj
= i915_gem_object_create_from_data(dev_priv
, fw
->data
, fw
->size
);
169 DRM_DEBUG_DRIVER("%s fw object_create err=%d\n",
170 intel_uc_fw_type_repr(uc_fw
->type
), err
);
175 uc_fw
->size
= fw
->size
;
176 uc_fw
->fetch_status
= INTEL_UC_FIRMWARE_SUCCESS
;
177 DRM_DEBUG_DRIVER("%s fw fetch %s\n",
178 intel_uc_fw_type_repr(uc_fw
->type
),
179 intel_uc_fw_status_repr(uc_fw
->fetch_status
));
181 release_firmware(fw
);
185 uc_fw
->fetch_status
= INTEL_UC_FIRMWARE_FAIL
;
186 DRM_DEBUG_DRIVER("%s fw fetch %s\n",
187 intel_uc_fw_type_repr(uc_fw
->type
),
188 intel_uc_fw_status_repr(uc_fw
->fetch_status
));
190 DRM_WARN("%s: Failed to fetch firmware %s (error %d)\n",
191 intel_uc_fw_type_repr(uc_fw
->type
), uc_fw
->path
, err
);
192 DRM_INFO("%s: Firmware can be downloaded from %s\n",
193 intel_uc_fw_type_repr(uc_fw
->type
), INTEL_UC_FIRMWARE_URL
);
195 release_firmware(fw
); /* OK even if fw is NULL */
199 * intel_uc_fw_upload - load uC firmware using custom loader
201 * @uc_fw: uC firmware
202 * @loader: custom uC firmware loader function
204 * Loads uC firmware using custom loader and updates internal flags.
206 int intel_uc_fw_upload(struct intel_uc_fw
*uc_fw
,
207 int (*xfer
)(struct intel_uc_fw
*uc_fw
,
208 struct i915_vma
*vma
))
210 struct i915_vma
*vma
;
213 DRM_DEBUG_DRIVER("%s fw load %s\n",
214 intel_uc_fw_type_repr(uc_fw
->type
), uc_fw
->path
);
216 if (uc_fw
->fetch_status
!= INTEL_UC_FIRMWARE_SUCCESS
)
219 uc_fw
->load_status
= INTEL_UC_FIRMWARE_PENDING
;
220 DRM_DEBUG_DRIVER("%s fw load %s\n",
221 intel_uc_fw_type_repr(uc_fw
->type
),
222 intel_uc_fw_status_repr(uc_fw
->load_status
));
224 /* Pin object with firmware */
225 err
= i915_gem_object_set_to_gtt_domain(uc_fw
->obj
, false);
227 DRM_DEBUG_DRIVER("%s fw set-domain err=%d\n",
228 intel_uc_fw_type_repr(uc_fw
->type
), err
);
232 vma
= i915_gem_object_ggtt_pin(uc_fw
->obj
, NULL
, 0, 0,
233 PIN_OFFSET_BIAS
| GUC_WOPCM_TOP
);
236 DRM_DEBUG_DRIVER("%s fw ggtt-pin err=%d\n",
237 intel_uc_fw_type_repr(uc_fw
->type
), err
);
241 /* Call custom loader */
242 err
= xfer(uc_fw
, vma
);
245 * We keep the object pages for reuse during resume. But we can unpin it
246 * now that DMA has completed, so it doesn't continue to take up space.
253 uc_fw
->load_status
= INTEL_UC_FIRMWARE_SUCCESS
;
254 DRM_DEBUG_DRIVER("%s fw load %s\n",
255 intel_uc_fw_type_repr(uc_fw
->type
),
256 intel_uc_fw_status_repr(uc_fw
->load_status
));
258 DRM_INFO("%s: Loaded firmware %s (version %u.%u)\n",
259 intel_uc_fw_type_repr(uc_fw
->type
),
261 uc_fw
->major_ver_found
, uc_fw
->minor_ver_found
);
266 uc_fw
->load_status
= INTEL_UC_FIRMWARE_FAIL
;
267 DRM_DEBUG_DRIVER("%s fw load %s\n",
268 intel_uc_fw_type_repr(uc_fw
->type
),
269 intel_uc_fw_status_repr(uc_fw
->load_status
));
271 DRM_WARN("%s: Failed to load firmware %s (error %d)\n",
272 intel_uc_fw_type_repr(uc_fw
->type
), uc_fw
->path
, err
);
278 * intel_uc_fw_fini - cleanup uC firmware
280 * @uc_fw: uC firmware
282 * Cleans up uC firmware by releasing the firmware GEM obj.
284 void intel_uc_fw_fini(struct intel_uc_fw
*uc_fw
)
286 struct drm_i915_gem_object
*obj
;
288 obj
= fetch_and_zero(&uc_fw
->obj
);
290 i915_gem_object_put(obj
);
292 uc_fw
->fetch_status
= INTEL_UC_FIRMWARE_NONE
;
296 * intel_uc_fw_dump - dump information about uC firmware
297 * @uc_fw: uC firmware
298 * @p: the &drm_printer
300 * Pretty printer for uC firmware.
302 void intel_uc_fw_dump(const struct intel_uc_fw
*uc_fw
, struct drm_printer
*p
)
304 drm_printf(p
, "%s firmware: %s\n",
305 intel_uc_fw_type_repr(uc_fw
->type
), uc_fw
->path
);
306 drm_printf(p
, "\tstatus: fetch %s, load %s\n",
307 intel_uc_fw_status_repr(uc_fw
->fetch_status
),
308 intel_uc_fw_status_repr(uc_fw
->load_status
));
309 drm_printf(p
, "\tversion: wanted %u.%u, found %u.%u\n",
310 uc_fw
->major_ver_wanted
, uc_fw
->minor_ver_wanted
,
311 uc_fw
->major_ver_found
, uc_fw
->minor_ver_found
);
312 drm_printf(p
, "\theader: offset %u, size %u\n",
313 uc_fw
->header_offset
, uc_fw
->header_size
);
314 drm_printf(p
, "\tuCode: offset %u, size %u\n",
315 uc_fw
->ucode_offset
, uc_fw
->ucode_size
);
316 drm_printf(p
, "\tRSA: offset %u, size %u\n",
317 uc_fw
->rsa_offset
, uc_fw
->rsa_size
);