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
);
99 if (css
->key_size_dw
!= UOS_RSA_SCRATCH_COUNT
) {
100 DRM_WARN("%s: Mismatched firmware RSA key size (%u)\n",
101 intel_uc_fw_type_repr(uc_fw
->type
), css
->key_size_dw
);
105 uc_fw
->rsa_offset
= uc_fw
->ucode_offset
+ uc_fw
->ucode_size
;
106 uc_fw
->rsa_size
= css
->key_size_dw
* sizeof(u32
);
108 /* At least, it should have header, uCode and RSA. Size of all three. */
109 size
= uc_fw
->header_size
+ uc_fw
->ucode_size
+ uc_fw
->rsa_size
;
110 if (fw
->size
< size
) {
111 DRM_WARN("%s: Truncated firmware (%zu, expected %zu)\n",
112 intel_uc_fw_type_repr(uc_fw
->type
), fw
->size
, size
);
118 * The GuC firmware image has the version number embedded at a
119 * well-known offset within the firmware blob; note that major / minor
120 * version are TWO bytes each (i.e. u16), although all pointers and
121 * offsets are defined in terms of bytes (u8).
123 switch (uc_fw
->type
) {
124 case INTEL_UC_FW_TYPE_GUC
:
125 uc_fw
->major_ver_found
= css
->guc
.sw_version
>> 16;
126 uc_fw
->minor_ver_found
= css
->guc
.sw_version
& 0xFFFF;
129 case INTEL_UC_FW_TYPE_HUC
:
130 uc_fw
->major_ver_found
= css
->huc
.sw_version
>> 16;
131 uc_fw
->minor_ver_found
= css
->huc
.sw_version
& 0xFFFF;
135 MISSING_CASE(uc_fw
->type
);
139 DRM_DEBUG_DRIVER("%s fw version %u.%u (wanted %u.%u)\n",
140 intel_uc_fw_type_repr(uc_fw
->type
),
141 uc_fw
->major_ver_found
, uc_fw
->minor_ver_found
,
142 uc_fw
->major_ver_wanted
, uc_fw
->minor_ver_wanted
);
144 if (uc_fw
->major_ver_wanted
== 0 && uc_fw
->minor_ver_wanted
== 0) {
145 DRM_NOTE("%s: Skipping firmware version check\n",
146 intel_uc_fw_type_repr(uc_fw
->type
));
147 } else if (uc_fw
->major_ver_found
!= uc_fw
->major_ver_wanted
||
148 uc_fw
->minor_ver_found
< uc_fw
->minor_ver_wanted
) {
149 DRM_NOTE("%s: Wrong firmware version (%u.%u, required %u.%u)\n",
150 intel_uc_fw_type_repr(uc_fw
->type
),
151 uc_fw
->major_ver_found
, uc_fw
->minor_ver_found
,
152 uc_fw
->major_ver_wanted
, uc_fw
->minor_ver_wanted
);
157 obj
= i915_gem_object_create_from_data(dev_priv
, fw
->data
, fw
->size
);
160 DRM_DEBUG_DRIVER("%s fw object_create err=%d\n",
161 intel_uc_fw_type_repr(uc_fw
->type
), err
);
166 uc_fw
->size
= fw
->size
;
167 uc_fw
->fetch_status
= INTEL_UC_FIRMWARE_SUCCESS
;
168 DRM_DEBUG_DRIVER("%s fw fetch %s\n",
169 intel_uc_fw_type_repr(uc_fw
->type
),
170 intel_uc_fw_status_repr(uc_fw
->fetch_status
));
172 release_firmware(fw
);
176 uc_fw
->fetch_status
= INTEL_UC_FIRMWARE_FAIL
;
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 DRM_WARN("%s: Failed to fetch firmware %s (error %d)\n",
182 intel_uc_fw_type_repr(uc_fw
->type
), uc_fw
->path
, err
);
183 DRM_INFO("%s: Firmware can be downloaded from %s\n",
184 intel_uc_fw_type_repr(uc_fw
->type
), INTEL_UC_FIRMWARE_URL
);
186 release_firmware(fw
); /* OK even if fw is NULL */
190 * intel_uc_fw_upload - load uC firmware using custom loader
191 * @uc_fw: uC firmware
192 * @xfer: custom uC firmware loader function
194 * Loads uC firmware using custom loader and updates internal flags.
196 * Return: 0 on success, non-zero on failure.
198 int intel_uc_fw_upload(struct intel_uc_fw
*uc_fw
,
199 int (*xfer
)(struct intel_uc_fw
*uc_fw
,
200 struct i915_vma
*vma
))
202 struct i915_vma
*vma
;
206 DRM_DEBUG_DRIVER("%s fw load %s\n",
207 intel_uc_fw_type_repr(uc_fw
->type
), uc_fw
->path
);
209 if (uc_fw
->fetch_status
!= INTEL_UC_FIRMWARE_SUCCESS
)
212 uc_fw
->load_status
= INTEL_UC_FIRMWARE_PENDING
;
213 DRM_DEBUG_DRIVER("%s fw load %s\n",
214 intel_uc_fw_type_repr(uc_fw
->type
),
215 intel_uc_fw_status_repr(uc_fw
->load_status
));
217 /* Pin object with firmware */
218 err
= i915_gem_object_set_to_gtt_domain(uc_fw
->obj
, false);
220 DRM_DEBUG_DRIVER("%s fw set-domain err=%d\n",
221 intel_uc_fw_type_repr(uc_fw
->type
), err
);
225 ggtt_pin_bias
= to_i915(uc_fw
->obj
->base
.dev
)->guc
.ggtt_pin_bias
;
226 vma
= i915_gem_object_ggtt_pin(uc_fw
->obj
, NULL
, 0, 0,
227 PIN_OFFSET_BIAS
| ggtt_pin_bias
);
230 DRM_DEBUG_DRIVER("%s fw ggtt-pin err=%d\n",
231 intel_uc_fw_type_repr(uc_fw
->type
), err
);
235 /* Call custom loader */
236 err
= xfer(uc_fw
, vma
);
239 * We keep the object pages for reuse during resume. But we can unpin it
240 * now that DMA has completed, so it doesn't continue to take up space.
247 uc_fw
->load_status
= INTEL_UC_FIRMWARE_SUCCESS
;
248 DRM_DEBUG_DRIVER("%s fw load %s\n",
249 intel_uc_fw_type_repr(uc_fw
->type
),
250 intel_uc_fw_status_repr(uc_fw
->load_status
));
252 DRM_INFO("%s: Loaded firmware %s (version %u.%u)\n",
253 intel_uc_fw_type_repr(uc_fw
->type
),
255 uc_fw
->major_ver_found
, uc_fw
->minor_ver_found
);
260 uc_fw
->load_status
= INTEL_UC_FIRMWARE_FAIL
;
261 DRM_DEBUG_DRIVER("%s fw load %s\n",
262 intel_uc_fw_type_repr(uc_fw
->type
),
263 intel_uc_fw_status_repr(uc_fw
->load_status
));
265 DRM_WARN("%s: Failed to load firmware %s (error %d)\n",
266 intel_uc_fw_type_repr(uc_fw
->type
), uc_fw
->path
, err
);
272 * intel_uc_fw_fini - cleanup uC firmware
274 * @uc_fw: uC firmware
276 * Cleans up uC firmware by releasing the firmware GEM obj.
278 void intel_uc_fw_fini(struct intel_uc_fw
*uc_fw
)
280 struct drm_i915_gem_object
*obj
;
282 obj
= fetch_and_zero(&uc_fw
->obj
);
284 i915_gem_object_put(obj
);
286 uc_fw
->fetch_status
= INTEL_UC_FIRMWARE_NONE
;
290 * intel_uc_fw_dump - dump information about uC firmware
291 * @uc_fw: uC firmware
292 * @p: the &drm_printer
294 * Pretty printer for uC firmware.
296 void intel_uc_fw_dump(const struct intel_uc_fw
*uc_fw
, struct drm_printer
*p
)
298 drm_printf(p
, "%s firmware: %s\n",
299 intel_uc_fw_type_repr(uc_fw
->type
), uc_fw
->path
);
300 drm_printf(p
, "\tstatus: fetch %s, load %s\n",
301 intel_uc_fw_status_repr(uc_fw
->fetch_status
),
302 intel_uc_fw_status_repr(uc_fw
->load_status
));
303 drm_printf(p
, "\tversion: wanted %u.%u, found %u.%u\n",
304 uc_fw
->major_ver_wanted
, uc_fw
->minor_ver_wanted
,
305 uc_fw
->major_ver_found
, uc_fw
->minor_ver_found
);
306 drm_printf(p
, "\theader: offset %u, size %u\n",
307 uc_fw
->header_offset
, uc_fw
->header_size
);
308 drm_printf(p
, "\tuCode: offset %u, size %u\n",
309 uc_fw
->ucode_offset
, uc_fw
->ucode_size
);
310 drm_printf(p
, "\tRSA: offset %u, size %u\n",
311 uc_fw
->rsa_offset
, uc_fw
->rsa_size
);