blob: 766b1cbdfbd773842129b9aea96989818037b307 [file] [log] [blame]
Michal Wajdeczkoa16b4312017-10-04 15:33:25 +00001/*
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/firmware.h>
26
27#include "intel_uc_fw.h"
28#include "i915_drv.h"
29
30/**
31 * intel_uc_fw_fetch - fetch uC firmware
32 *
33 * @dev_priv: device private
34 * @uc_fw: uC firmware
35 *
36 * Fetch uC firmware into GEM obj.
37 */
38void intel_uc_fw_fetch(struct drm_i915_private *dev_priv,
39 struct intel_uc_fw *uc_fw)
40{
41 struct pci_dev *pdev = dev_priv->drm.pdev;
42 struct drm_i915_gem_object *obj;
43 const struct firmware *fw = NULL;
44 struct uc_css_header *css;
45 size_t size;
46 int err;
47
48 if (!uc_fw->path)
49 return;
50
51 uc_fw->fetch_status = INTEL_UC_FIRMWARE_PENDING;
52
53 DRM_DEBUG_DRIVER("before requesting firmware: uC fw fetch status %s\n",
54 intel_uc_fw_status_repr(uc_fw->fetch_status));
55
56 err = request_firmware(&fw, uc_fw->path, &pdev->dev);
57 if (err)
58 goto fail;
59 if (!fw)
60 goto fail;
61
62 DRM_DEBUG_DRIVER("fetch uC fw from %s succeeded, fw %p\n",
63 uc_fw->path, fw);
64
65 /* Check the size of the blob before examining buffer contents */
66 if (fw->size < sizeof(struct uc_css_header)) {
67 DRM_NOTE("Firmware header is missing\n");
68 goto fail;
69 }
70
71 css = (struct uc_css_header *)fw->data;
72
73 /* Firmware bits always start from header */
74 uc_fw->header_offset = 0;
75 uc_fw->header_size = (css->header_size_dw - css->modulus_size_dw -
76 css->key_size_dw - css->exponent_size_dw) *
77 sizeof(u32);
78
79 if (uc_fw->header_size != sizeof(struct uc_css_header)) {
80 DRM_NOTE("CSS header definition mismatch\n");
81 goto fail;
82 }
83
84 /* then, uCode */
85 uc_fw->ucode_offset = uc_fw->header_offset + uc_fw->header_size;
86 uc_fw->ucode_size = (css->size_dw - css->header_size_dw) * sizeof(u32);
87
88 /* now RSA */
89 if (css->key_size_dw != UOS_RSA_SCRATCH_MAX_COUNT) {
90 DRM_NOTE("RSA key size is bad\n");
91 goto fail;
92 }
93 uc_fw->rsa_offset = uc_fw->ucode_offset + uc_fw->ucode_size;
94 uc_fw->rsa_size = css->key_size_dw * sizeof(u32);
95
96 /* At least, it should have header, uCode and RSA. Size of all three. */
97 size = uc_fw->header_size + uc_fw->ucode_size + uc_fw->rsa_size;
98 if (fw->size < size) {
99 DRM_NOTE("Missing firmware components\n");
100 goto fail;
101 }
102
103 /*
104 * The GuC firmware image has the version number embedded at a
105 * well-known offset within the firmware blob; note that major / minor
106 * version are TWO bytes each (i.e. u16), although all pointers and
107 * offsets are defined in terms of bytes (u8).
108 */
109 switch (uc_fw->type) {
110 case INTEL_UC_FW_TYPE_GUC:
111 /* Header and uCode will be loaded to WOPCM. Size of the two. */
112 size = uc_fw->header_size + uc_fw->ucode_size;
113
114 /* Top 32k of WOPCM is reserved (8K stack + 24k RC6 context). */
115 if (size > intel_guc_wopcm_size(dev_priv)) {
116 DRM_ERROR("Firmware is too large to fit in WOPCM\n");
117 goto fail;
118 }
119 uc_fw->major_ver_found = css->guc.sw_version >> 16;
120 uc_fw->minor_ver_found = css->guc.sw_version & 0xFFFF;
121 break;
122
123 case INTEL_UC_FW_TYPE_HUC:
124 uc_fw->major_ver_found = css->huc.sw_version >> 16;
125 uc_fw->minor_ver_found = css->huc.sw_version & 0xFFFF;
126 break;
127
128 default:
129 DRM_ERROR("Unknown firmware type %d\n", uc_fw->type);
130 err = -ENOEXEC;
131 goto fail;
132 }
133
134 if (uc_fw->major_ver_wanted == 0 && uc_fw->minor_ver_wanted == 0) {
135 DRM_NOTE("Skipping %s firmware version check\n",
136 intel_uc_fw_type_repr(uc_fw->type));
137 } else if (uc_fw->major_ver_found != uc_fw->major_ver_wanted ||
138 uc_fw->minor_ver_found < uc_fw->minor_ver_wanted) {
139 DRM_NOTE("%s firmware version %d.%d, required %d.%d\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);
143 err = -ENOEXEC;
144 goto fail;
145 }
146
147 DRM_DEBUG_DRIVER("firmware version %d.%d OK (minimum %d.%d)\n",
148 uc_fw->major_ver_found, uc_fw->minor_ver_found,
149 uc_fw->major_ver_wanted, uc_fw->minor_ver_wanted);
150
151 obj = i915_gem_object_create_from_data(dev_priv, fw->data, fw->size);
152 if (IS_ERR(obj)) {
153 err = PTR_ERR(obj);
154 goto fail;
155 }
156
157 uc_fw->obj = obj;
158 uc_fw->size = fw->size;
159
160 DRM_DEBUG_DRIVER("uC fw fetch status SUCCESS, obj %p\n",
161 uc_fw->obj);
162
163 release_firmware(fw);
164 uc_fw->fetch_status = INTEL_UC_FIRMWARE_SUCCESS;
165 return;
166
167fail:
168 DRM_WARN("Failed to fetch valid uC firmware from %s (error %d)\n",
169 uc_fw->path, err);
170 DRM_DEBUG_DRIVER("uC fw fetch status FAIL; err %d, fw %p, obj %p\n",
171 err, fw, uc_fw->obj);
172
173 release_firmware(fw); /* OK even if fw is NULL */
174 uc_fw->fetch_status = INTEL_UC_FIRMWARE_FAIL;
175}
176
177/**
178 * intel_uc_fw_fini - cleanup uC firmware
179 *
180 * @uc_fw: uC firmware
181 *
182 * Cleans up uC firmware by releasing the firmware GEM obj.
183 */
184void intel_uc_fw_fini(struct intel_uc_fw *uc_fw)
185{
186 struct drm_i915_gem_object *obj;
187
188 obj = fetch_and_zero(&uc_fw->obj);
189 if (obj)
190 i915_gem_object_put(obj);
191
192 uc_fw->fetch_status = INTEL_UC_FIRMWARE_NONE;
193}