File: | dev/pci/drm/i915/gt/uc/intel_uc_fw.c |
Warning: | line 301, column 6 Access to field 'size' results in a dereference of a null pointer (loaded from variable 'fw') |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | // SPDX-License-Identifier: MIT | ||||
2 | /* | ||||
3 | * Copyright © 2016-2019 Intel Corporation | ||||
4 | */ | ||||
5 | |||||
6 | #include <linux/bitfield.h> | ||||
7 | #include <linux/firmware.h> | ||||
8 | #include <drm/drm_print.h> | ||||
9 | |||||
10 | #include "intel_uc_fw.h" | ||||
11 | #include "intel_uc_fw_abi.h" | ||||
12 | #include "i915_drv.h" | ||||
13 | |||||
14 | static inline struct intel_gt * | ||||
15 | ____uc_fw_to_gt(struct intel_uc_fw *uc_fw, enum intel_uc_fw_type type) | ||||
16 | { | ||||
17 | if (type == INTEL_UC_FW_TYPE_GUC) | ||||
18 | return container_of(uc_fw, struct intel_gt, uc.guc.fw)({ const __typeof( ((struct intel_gt *)0)->uc.guc.fw ) *__mptr = (uc_fw); (struct intel_gt *)( (char *)__mptr - __builtin_offsetof (struct intel_gt, uc.guc.fw) );}); | ||||
19 | |||||
20 | GEM_BUG_ON(type != INTEL_UC_FW_TYPE_HUC)((void)0); | ||||
21 | return container_of(uc_fw, struct intel_gt, uc.huc.fw)({ const __typeof( ((struct intel_gt *)0)->uc.huc.fw ) *__mptr = (uc_fw); (struct intel_gt *)( (char *)__mptr - __builtin_offsetof (struct intel_gt, uc.huc.fw) );}); | ||||
22 | } | ||||
23 | |||||
24 | static inline struct intel_gt *__uc_fw_to_gt(struct intel_uc_fw *uc_fw) | ||||
25 | { | ||||
26 | GEM_BUG_ON(uc_fw->status == INTEL_UC_FIRMWARE_UNINITIALIZED)((void)0); | ||||
27 | return ____uc_fw_to_gt(uc_fw, uc_fw->type); | ||||
28 | } | ||||
29 | |||||
30 | #ifdef CONFIG_DRM_I915_DEBUG_GUC | ||||
31 | void intel_uc_fw_change_status(struct intel_uc_fw *uc_fw, | ||||
32 | enum intel_uc_fw_status status) | ||||
33 | { | ||||
34 | uc_fw->__status = status; | ||||
35 | drm_dbg(&__uc_fw_to_gt(uc_fw)->i915->drm,drm_dev_dbg((&__uc_fw_to_gt(uc_fw)->i915->drm)-> dev, DRM_UT_DRIVER, "%s firmware -> %s\n", intel_uc_fw_type_repr (uc_fw->type), status == INTEL_UC_FIRMWARE_SELECTED ? uc_fw ->path : intel_uc_fw_status_repr(status)) | ||||
36 | "%s firmware -> %s\n",drm_dev_dbg((&__uc_fw_to_gt(uc_fw)->i915->drm)-> dev, DRM_UT_DRIVER, "%s firmware -> %s\n", intel_uc_fw_type_repr (uc_fw->type), status == INTEL_UC_FIRMWARE_SELECTED ? uc_fw ->path : intel_uc_fw_status_repr(status)) | ||||
37 | intel_uc_fw_type_repr(uc_fw->type),drm_dev_dbg((&__uc_fw_to_gt(uc_fw)->i915->drm)-> dev, DRM_UT_DRIVER, "%s firmware -> %s\n", intel_uc_fw_type_repr (uc_fw->type), status == INTEL_UC_FIRMWARE_SELECTED ? uc_fw ->path : intel_uc_fw_status_repr(status)) | ||||
38 | status == INTEL_UC_FIRMWARE_SELECTED ?drm_dev_dbg((&__uc_fw_to_gt(uc_fw)->i915->drm)-> dev, DRM_UT_DRIVER, "%s firmware -> %s\n", intel_uc_fw_type_repr (uc_fw->type), status == INTEL_UC_FIRMWARE_SELECTED ? uc_fw ->path : intel_uc_fw_status_repr(status)) | ||||
39 | uc_fw->path : intel_uc_fw_status_repr(status))drm_dev_dbg((&__uc_fw_to_gt(uc_fw)->i915->drm)-> dev, DRM_UT_DRIVER, "%s firmware -> %s\n", intel_uc_fw_type_repr (uc_fw->type), status == INTEL_UC_FIRMWARE_SELECTED ? uc_fw ->path : intel_uc_fw_status_repr(status)); | ||||
40 | } | ||||
41 | #endif | ||||
42 | |||||
43 | /* | ||||
44 | * List of required GuC and HuC binaries per-platform. | ||||
45 | * Must be ordered based on platform + revid, from newer to older. | ||||
46 | * | ||||
47 | * TGL 35.2 is interface-compatible with 33.0 for previous Gens. The deltas | ||||
48 | * between 33.0 and 35.2 are only related to new additions to support new Gen12 | ||||
49 | * features. | ||||
50 | * | ||||
51 | * Note that RKL uses the same firmware as TGL. | ||||
52 | */ | ||||
53 | #define INTEL_UC_FIRMWARE_DEFS(fw_def, guc_def, huc_def)fw_def(ROCKETLAKE, 0, guc_def(tgl, 35, 2, 0), huc_def(tgl, 7, 5, 0)) fw_def(TIGERLAKE, 0, guc_def(tgl, 35, 2, 0), huc_def( tgl, 7, 5, 0)) fw_def(ELKHARTLAKE, 0, guc_def(ehl, 33, 0, 4), huc_def(ehl, 9, 0, 0)) fw_def(ICELAKE, 0, guc_def(icl, 33, 0 , 0), huc_def(icl, 9, 0, 0)) fw_def(COMETLAKE, 5, guc_def(cml , 33, 0, 0), huc_def(cml, 4, 0, 0)) fw_def(COFFEELAKE, 0, guc_def (kbl, 33, 0, 0), huc_def(kbl, 4, 0, 0)) fw_def(GEMINILAKE, 0, guc_def(glk, 33, 0, 0), huc_def(glk, 4, 0, 0)) fw_def(KABYLAKE , 0, guc_def(kbl, 33, 0, 0), huc_def(kbl, 4, 0, 0)) fw_def(BROXTON , 0, guc_def(bxt, 33, 0, 0), huc_def(bxt, 2, 0, 0)) fw_def(SKYLAKE , 0, guc_def(skl, 33, 0, 0), huc_def(skl, 2, 0, 0)) \ | ||||
54 | fw_def(ROCKETLAKE, 0, guc_def(tgl, 35, 2, 0), huc_def(tgl, 7, 5, 0)) \ | ||||
55 | fw_def(TIGERLAKE, 0, guc_def(tgl, 35, 2, 0), huc_def(tgl, 7, 5, 0)) \ | ||||
56 | fw_def(ELKHARTLAKE, 0, guc_def(ehl, 33, 0, 4), huc_def(ehl, 9, 0, 0)) \ | ||||
57 | fw_def(ICELAKE, 0, guc_def(icl, 33, 0, 0), huc_def(icl, 9, 0, 0)) \ | ||||
58 | fw_def(COMETLAKE, 5, guc_def(cml, 33, 0, 0), huc_def(cml, 4, 0, 0)) \ | ||||
59 | fw_def(COFFEELAKE, 0, guc_def(kbl, 33, 0, 0), huc_def(kbl, 4, 0, 0)) \ | ||||
60 | fw_def(GEMINILAKE, 0, guc_def(glk, 33, 0, 0), huc_def(glk, 4, 0, 0)) \ | ||||
61 | fw_def(KABYLAKE, 0, guc_def(kbl, 33, 0, 0), huc_def(kbl, 4, 0, 0)) \ | ||||
62 | fw_def(BROXTON, 0, guc_def(bxt, 33, 0, 0), huc_def(bxt, 2, 0, 0)) \ | ||||
63 | fw_def(SKYLAKE, 0, guc_def(skl, 33, 0, 0), huc_def(skl, 2, 0, 0)) | ||||
64 | |||||
65 | #define __MAKE_UC_FW_PATH(prefix_, name_, major_, minor_, patch_)"i915/" "prefix_" name_ "major_" "." "minor_" "." "patch_" ".bin" \ | ||||
66 | "i915/" \ | ||||
67 | __stringify(prefix_)"prefix_" name_ \ | ||||
68 | __stringify(major_)"major_" "." \ | ||||
69 | __stringify(minor_)"minor_" "." \ | ||||
70 | __stringify(patch_)"patch_" ".bin" | ||||
71 | |||||
72 | #define MAKE_GUC_FW_PATH(prefix_, major_, minor_, patch_)"i915/" "prefix_" "_guc_" "major_" "." "minor_" "." "patch_" ".bin" \ | ||||
73 | __MAKE_UC_FW_PATH(prefix_, "_guc_", major_, minor_, patch_)"i915/" "prefix_" "_guc_" "major_" "." "minor_" "." "patch_" ".bin" | ||||
74 | |||||
75 | #define MAKE_HUC_FW_PATH(prefix_, major_, minor_, bld_num_)"i915/" "prefix_" "_huc_" "major_" "." "minor_" "." "bld_num_" ".bin" \ | ||||
76 | __MAKE_UC_FW_PATH(prefix_, "_huc_", major_, minor_, bld_num_)"i915/" "prefix_" "_huc_" "major_" "." "minor_" "." "bld_num_" ".bin" | ||||
77 | |||||
78 | /* All blobs need to be declared via MODULE_FIRMWARE() */ | ||||
79 | #define INTEL_UC_MODULE_FW(platform_, revid_, guc_, huc_); ; \ | ||||
80 | MODULE_FIRMWARE(guc_); \ | ||||
81 | MODULE_FIRMWARE(huc_); | ||||
82 | |||||
83 | INTEL_UC_FIRMWARE_DEFS(INTEL_UC_MODULE_FW, MAKE_GUC_FW_PATH, MAKE_HUC_FW_PATH); ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; | ||||
84 | |||||
85 | /* The below structs and macros are used to iterate across the list of blobs */ | ||||
86 | struct __packed__attribute__((__packed__)) uc_fw_blob { | ||||
87 | u8 major; | ||||
88 | u8 minor; | ||||
89 | const char *path; | ||||
90 | }; | ||||
91 | |||||
92 | #define UC_FW_BLOB(major_, minor_, path_){ .major = major_, .minor = minor_, .path = path_ } \ | ||||
93 | { .major = major_, .minor = minor_, .path = path_ } | ||||
94 | |||||
95 | #define GUC_FW_BLOB(prefix_, major_, minor_, patch_){ .major = major_, .minor = minor_, .path = "i915/" "prefix_" "_guc_" "major_" "." "minor_" "." "patch_" ".bin" } \ | ||||
96 | UC_FW_BLOB(major_, minor_, \{ .major = major_, .minor = minor_, .path = "i915/" "prefix_" "_guc_" "major_" "." "minor_" "." "patch_" ".bin" } | ||||
97 | MAKE_GUC_FW_PATH(prefix_, major_, minor_, patch_)){ .major = major_, .minor = minor_, .path = "i915/" "prefix_" "_guc_" "major_" "." "minor_" "." "patch_" ".bin" } | ||||
98 | |||||
99 | #define HUC_FW_BLOB(prefix_, major_, minor_, bld_num_){ .major = major_, .minor = minor_, .path = "i915/" "prefix_" "_huc_" "major_" "." "minor_" "." "bld_num_" ".bin" } \ | ||||
100 | UC_FW_BLOB(major_, minor_, \{ .major = major_, .minor = minor_, .path = "i915/" "prefix_" "_huc_" "major_" "." "minor_" "." "bld_num_" ".bin" } | ||||
101 | MAKE_HUC_FW_PATH(prefix_, major_, minor_, bld_num_)){ .major = major_, .minor = minor_, .path = "i915/" "prefix_" "_huc_" "major_" "." "minor_" "." "bld_num_" ".bin" } | ||||
102 | |||||
103 | struct __packed__attribute__((__packed__)) uc_fw_platform_requirement { | ||||
104 | enum intel_platform p; | ||||
105 | u8 rev; /* first platform rev using this FW */ | ||||
106 | const struct uc_fw_blob blobs[INTEL_UC_FW_NUM_TYPES2]; | ||||
107 | }; | ||||
108 | |||||
109 | #define MAKE_FW_LIST(platform_, revid_, guc_, huc_){ .p = INTEL_platform_, .rev = revid_, .blobs[INTEL_UC_FW_TYPE_GUC ] = guc_, .blobs[INTEL_UC_FW_TYPE_HUC] = huc_, }, \ | ||||
110 | { \ | ||||
111 | .p = INTEL_##platform_, \ | ||||
112 | .rev = revid_, \ | ||||
113 | .blobs[INTEL_UC_FW_TYPE_GUC] = guc_, \ | ||||
114 | .blobs[INTEL_UC_FW_TYPE_HUC] = huc_, \ | ||||
115 | }, | ||||
116 | |||||
117 | static void | ||||
118 | __uc_fw_auto_select(struct drm_i915_privateinteldrm_softc *i915, struct intel_uc_fw *uc_fw) | ||||
119 | { | ||||
120 | static const struct uc_fw_platform_requirement fw_blobs[] = { | ||||
121 | INTEL_UC_FIRMWARE_DEFS(MAKE_FW_LIST, GUC_FW_BLOB, HUC_FW_BLOB){ .p = INTEL_ROCKETLAKE, .rev = 0, .blobs[INTEL_UC_FW_TYPE_GUC ] = { .major = 35, .minor = 2, .path = "i915/" "tgl" "_guc_" "35" "." "2" "." "0" ".bin" }, .blobs[INTEL_UC_FW_TYPE_HUC] = { . major = 7, .minor = 5, .path = "i915/" "tgl" "_huc_" "7" "." "5" "." "0" ".bin" }, }, { .p = INTEL_TIGERLAKE, .rev = 0, .blobs [INTEL_UC_FW_TYPE_GUC] = { .major = 35, .minor = 2, .path = "i915/" "tgl" "_guc_" "35" "." "2" "." "0" ".bin" }, .blobs[INTEL_UC_FW_TYPE_HUC ] = { .major = 7, .minor = 5, .path = "i915/" "tgl" "_huc_" "7" "." "5" "." "0" ".bin" }, }, { .p = INTEL_ELKHARTLAKE, .rev = 0, .blobs[INTEL_UC_FW_TYPE_GUC] = { .major = 33, .minor = 0, .path = "i915/" "ehl" "_guc_" "33" "." "0" "." "4" ".bin" }, .blobs[INTEL_UC_FW_TYPE_HUC] = { .major = 9, .minor = 0, .path = "i915/" "ehl" "_huc_" "9" "." "0" "." "0" ".bin" }, }, { . p = INTEL_ICELAKE, .rev = 0, .blobs[INTEL_UC_FW_TYPE_GUC] = { .major = 33, .minor = 0, .path = "i915/" "icl" "_guc_" "33" "." "0" "." "0" ".bin" }, .blobs[INTEL_UC_FW_TYPE_HUC] = { .major = 9, .minor = 0, .path = "i915/" "icl" "_huc_" "9" "." "0" "." "0" ".bin" }, }, { .p = INTEL_COMETLAKE, .rev = 5, .blobs[INTEL_UC_FW_TYPE_GUC ] = { .major = 33, .minor = 0, .path = "i915/" "cml" "_guc_" "33" "." "0" "." "0" ".bin" }, .blobs[INTEL_UC_FW_TYPE_HUC] = { . major = 4, .minor = 0, .path = "i915/" "cml" "_huc_" "4" "." "0" "." "0" ".bin" }, }, { .p = INTEL_COFFEELAKE, .rev = 0, .blobs [INTEL_UC_FW_TYPE_GUC] = { .major = 33, .minor = 0, .path = "i915/" "kbl" "_guc_" "33" "." "0" "." "0" ".bin" }, .blobs[INTEL_UC_FW_TYPE_HUC ] = { .major = 4, .minor = 0, .path = "i915/" "kbl" "_huc_" "4" "." "0" "." "0" ".bin" }, }, { .p = INTEL_GEMINILAKE, .rev = 0, .blobs[INTEL_UC_FW_TYPE_GUC] = { .major = 33, .minor = 0, .path = "i915/" "glk" "_guc_" "33" "." "0" "." "0" ".bin" }, .blobs[INTEL_UC_FW_TYPE_HUC] = { .major = 4, .minor = 0, .path = "i915/" "glk" "_huc_" "4" "." "0" "." "0" ".bin" }, }, { . p = INTEL_KABYLAKE, .rev = 0, .blobs[INTEL_UC_FW_TYPE_GUC] = { .major = 33, .minor = 0, .path = "i915/" "kbl" "_guc_" "33" "." "0" "." "0" ".bin" }, .blobs[INTEL_UC_FW_TYPE_HUC] = { .major = 4, .minor = 0, .path = "i915/" "kbl" "_huc_" "4" "." "0" "." "0" ".bin" }, }, { .p = INTEL_BROXTON, .rev = 0, .blobs[INTEL_UC_FW_TYPE_GUC ] = { .major = 33, .minor = 0, .path = "i915/" "bxt" "_guc_" "33" "." "0" "." "0" ".bin" }, .blobs[INTEL_UC_FW_TYPE_HUC] = { . major = 2, .minor = 0, .path = "i915/" "bxt" "_huc_" "2" "." "0" "." "0" ".bin" }, }, { .p = INTEL_SKYLAKE, .rev = 0, .blobs[ INTEL_UC_FW_TYPE_GUC] = { .major = 33, .minor = 0, .path = "i915/" "skl" "_guc_" "33" "." "0" "." "0" ".bin" }, .blobs[INTEL_UC_FW_TYPE_HUC ] = { .major = 2, .minor = 0, .path = "i915/" "skl" "_huc_" "2" "." "0" "." "0" ".bin" }, }, | ||||
122 | }; | ||||
123 | enum intel_platform p = INTEL_INFO(i915)(&(i915)->__info)->platform; | ||||
124 | u8 rev = INTEL_REVID(i915)((i915)->drm.pdev->revision); | ||||
125 | int i; | ||||
126 | |||||
127 | for (i = 0; i < ARRAY_SIZE(fw_blobs)(sizeof((fw_blobs)) / sizeof((fw_blobs)[0])) && p <= fw_blobs[i].p; i++) { | ||||
128 | if (p == fw_blobs[i].p && rev >= fw_blobs[i].rev) { | ||||
129 | const struct uc_fw_blob *blob = | ||||
130 | &fw_blobs[i].blobs[uc_fw->type]; | ||||
131 | uc_fw->path = blob->path; | ||||
132 | uc_fw->major_ver_wanted = blob->major; | ||||
133 | uc_fw->minor_ver_wanted = blob->minor; | ||||
134 | break; | ||||
135 | } | ||||
136 | } | ||||
137 | |||||
138 | /* make sure the list is ordered as expected */ | ||||
139 | if (IS_ENABLED(CONFIG_DRM_I915_SELFTEST)0) { | ||||
140 | for (i = 1; i < ARRAY_SIZE(fw_blobs)(sizeof((fw_blobs)) / sizeof((fw_blobs)[0])); i++) { | ||||
141 | if (fw_blobs[i].p < fw_blobs[i - 1].p) | ||||
142 | continue; | ||||
143 | |||||
144 | if (fw_blobs[i].p == fw_blobs[i - 1].p && | ||||
145 | fw_blobs[i].rev < fw_blobs[i - 1].rev) | ||||
146 | continue; | ||||
147 | |||||
148 | pr_err("invalid FW blob order: %s r%u comes before %s r%u\n",printk("\0013" "invalid FW blob order: %s r%u comes before %s r%u\n" , intel_platform_name(fw_blobs[i - 1].p), fw_blobs[i - 1].rev , intel_platform_name(fw_blobs[i].p), fw_blobs[i].rev) | ||||
149 | intel_platform_name(fw_blobs[i - 1].p),printk("\0013" "invalid FW blob order: %s r%u comes before %s r%u\n" , intel_platform_name(fw_blobs[i - 1].p), fw_blobs[i - 1].rev , intel_platform_name(fw_blobs[i].p), fw_blobs[i].rev) | ||||
150 | fw_blobs[i - 1].rev,printk("\0013" "invalid FW blob order: %s r%u comes before %s r%u\n" , intel_platform_name(fw_blobs[i - 1].p), fw_blobs[i - 1].rev , intel_platform_name(fw_blobs[i].p), fw_blobs[i].rev) | ||||
151 | intel_platform_name(fw_blobs[i].p),printk("\0013" "invalid FW blob order: %s r%u comes before %s r%u\n" , intel_platform_name(fw_blobs[i - 1].p), fw_blobs[i - 1].rev , intel_platform_name(fw_blobs[i].p), fw_blobs[i].rev) | ||||
152 | fw_blobs[i].rev)printk("\0013" "invalid FW blob order: %s r%u comes before %s r%u\n" , intel_platform_name(fw_blobs[i - 1].p), fw_blobs[i - 1].rev , intel_platform_name(fw_blobs[i].p), fw_blobs[i].rev); | ||||
153 | |||||
154 | uc_fw->path = NULL((void *)0); | ||||
155 | } | ||||
156 | } | ||||
157 | |||||
158 | /* We don't want to enable GuC/HuC on pre-Gen11 by default */ | ||||
159 | if (i915->params.enable_guc == -1 && p < INTEL_ICELAKE) | ||||
160 | uc_fw->path = NULL((void *)0); | ||||
161 | } | ||||
162 | |||||
163 | static const char *__override_guc_firmware_path(struct drm_i915_privateinteldrm_softc *i915) | ||||
164 | { | ||||
165 | if (i915->params.enable_guc & (ENABLE_GUC_SUBMISSION(1UL << (0)) | | ||||
166 | ENABLE_GUC_LOAD_HUC(1UL << (1)))) | ||||
167 | return i915->params.guc_firmware_path; | ||||
168 | return ""; | ||||
169 | } | ||||
170 | |||||
171 | static const char *__override_huc_firmware_path(struct drm_i915_privateinteldrm_softc *i915) | ||||
172 | { | ||||
173 | if (i915->params.enable_guc & ENABLE_GUC_LOAD_HUC(1UL << (1))) | ||||
174 | return i915->params.huc_firmware_path; | ||||
175 | return ""; | ||||
176 | } | ||||
177 | |||||
178 | static void __uc_fw_user_override(struct drm_i915_privateinteldrm_softc *i915, struct intel_uc_fw *uc_fw) | ||||
179 | { | ||||
180 | const char *path = NULL((void *)0); | ||||
181 | |||||
182 | switch (uc_fw->type) { | ||||
183 | case INTEL_UC_FW_TYPE_GUC: | ||||
184 | path = __override_guc_firmware_path(i915); | ||||
185 | break; | ||||
186 | case INTEL_UC_FW_TYPE_HUC: | ||||
187 | path = __override_huc_firmware_path(i915); | ||||
188 | break; | ||||
189 | } | ||||
190 | |||||
191 | if (unlikely(path)__builtin_expect(!!(path), 0)) { | ||||
192 | uc_fw->path = path; | ||||
193 | uc_fw->user_overridden = true1; | ||||
194 | } | ||||
195 | } | ||||
196 | |||||
197 | /** | ||||
198 | * intel_uc_fw_init_early - initialize the uC object and select the firmware | ||||
199 | * @uc_fw: uC firmware | ||||
200 | * @type: type of uC | ||||
201 | * | ||||
202 | * Initialize the state of our uC object and relevant tracking and select the | ||||
203 | * firmware to fetch and load. | ||||
204 | */ | ||||
205 | void intel_uc_fw_init_early(struct intel_uc_fw *uc_fw, | ||||
206 | enum intel_uc_fw_type type) | ||||
207 | { | ||||
208 | struct drm_i915_privateinteldrm_softc *i915 = ____uc_fw_to_gt(uc_fw, type)->i915; | ||||
209 | |||||
210 | /* | ||||
211 | * we use FIRMWARE_UNINITIALIZED to detect checks against uc_fw->status | ||||
212 | * before we're looked at the HW caps to see if we have uc support | ||||
213 | */ | ||||
214 | BUILD_BUG_ON(INTEL_UC_FIRMWARE_UNINITIALIZED)extern char _ctassert[(!(INTEL_UC_FIRMWARE_UNINITIALIZED)) ? 1 : -1 ] __attribute__((__unused__)); | ||||
215 | GEM_BUG_ON(uc_fw->status)((void)0); | ||||
216 | GEM_BUG_ON(uc_fw->path)((void)0); | ||||
217 | |||||
218 | uc_fw->type = type; | ||||
219 | |||||
220 | if (HAS_GT_UC(i915)((&(i915)->__info)->has_gt_uc)) { | ||||
221 | __uc_fw_auto_select(i915, uc_fw); | ||||
222 | __uc_fw_user_override(i915, uc_fw); | ||||
223 | } | ||||
224 | |||||
225 | intel_uc_fw_change_status(uc_fw, uc_fw->path ? *uc_fw->path ? | ||||
226 | INTEL_UC_FIRMWARE_SELECTED : | ||||
227 | INTEL_UC_FIRMWARE_DISABLED : | ||||
228 | INTEL_UC_FIRMWARE_NOT_SUPPORTED); | ||||
229 | } | ||||
230 | |||||
231 | static void __force_fw_fetch_failures(struct intel_uc_fw *uc_fw, int e) | ||||
232 | { | ||||
233 | struct drm_i915_privateinteldrm_softc *i915 = __uc_fw_to_gt(uc_fw)->i915; | ||||
234 | bool_Bool user = e == -EINVAL22; | ||||
235 | |||||
236 | if (i915_inject_probe_error(i915, e)({ ((void)0); 0; })) { | ||||
237 | /* non-existing blob */ | ||||
238 | uc_fw->path = "<invalid>"; | ||||
239 | uc_fw->user_overridden = user; | ||||
240 | } else if (i915_inject_probe_error(i915, e)({ ((void)0); 0; })) { | ||||
241 | /* require next major version */ | ||||
242 | uc_fw->major_ver_wanted += 1; | ||||
243 | uc_fw->minor_ver_wanted = 0; | ||||
244 | uc_fw->user_overridden = user; | ||||
245 | } else if (i915_inject_probe_error(i915, e)({ ((void)0); 0; })) { | ||||
246 | /* require next minor version */ | ||||
247 | uc_fw->minor_ver_wanted += 1; | ||||
248 | uc_fw->user_overridden = user; | ||||
249 | } else if (uc_fw->major_ver_wanted && | ||||
250 | i915_inject_probe_error(i915, e)({ ((void)0); 0; })) { | ||||
251 | /* require prev major version */ | ||||
252 | uc_fw->major_ver_wanted -= 1; | ||||
253 | uc_fw->minor_ver_wanted = 0; | ||||
254 | uc_fw->user_overridden = user; | ||||
255 | } else if (uc_fw->minor_ver_wanted && | ||||
256 | i915_inject_probe_error(i915, e)({ ((void)0); 0; })) { | ||||
257 | /* require prev minor version - hey, this should work! */ | ||||
258 | uc_fw->minor_ver_wanted -= 1; | ||||
259 | uc_fw->user_overridden = user; | ||||
260 | } else if (user && i915_inject_probe_error(i915, e)({ ((void)0); 0; })) { | ||||
261 | /* officially unsupported platform */ | ||||
262 | uc_fw->major_ver_wanted = 0; | ||||
263 | uc_fw->minor_ver_wanted = 0; | ||||
264 | uc_fw->user_overridden = true1; | ||||
265 | } | ||||
266 | } | ||||
267 | |||||
268 | /** | ||||
269 | * intel_uc_fw_fetch - fetch uC firmware | ||||
270 | * @uc_fw: uC firmware | ||||
271 | * | ||||
272 | * Fetch uC firmware into GEM obj. | ||||
273 | * | ||||
274 | * Return: 0 on success, a negative errno code on failure. | ||||
275 | */ | ||||
276 | int intel_uc_fw_fetch(struct intel_uc_fw *uc_fw) | ||||
277 | { | ||||
278 | struct drm_i915_privateinteldrm_softc *i915 = __uc_fw_to_gt(uc_fw)->i915; | ||||
279 | struct device *dev = i915->drm.dev; | ||||
280 | struct drm_i915_gem_object *obj; | ||||
281 | const struct firmware *fw = NULL((void *)0); | ||||
282 | struct uc_css_header *css; | ||||
283 | size_t size; | ||||
284 | int err; | ||||
285 | |||||
286 | GEM_BUG_ON(!i915->wopcm.size)((void)0); | ||||
287 | GEM_BUG_ON(!intel_uc_fw_is_enabled(uc_fw))((void)0); | ||||
288 | |||||
289 | err = i915_inject_probe_error(i915, -ENXIO)({ ((void)0); 0; }); | ||||
290 | if (err
| ||||
| |||||
291 | goto fail; | ||||
292 | |||||
293 | __force_fw_fetch_failures(uc_fw, -EINVAL22); | ||||
294 | __force_fw_fetch_failures(uc_fw, -ESTALE70); | ||||
295 | |||||
296 | err = request_firmware(&fw, uc_fw->path, dev); | ||||
297 | if (err) | ||||
298 | goto fail; | ||||
299 | |||||
300 | /* Check the size of the blob before examining buffer contents */ | ||||
301 | if (unlikely(fw->size < sizeof(struct uc_css_header))__builtin_expect(!!(fw->size < sizeof(struct uc_css_header )), 0)) { | ||||
| |||||
302 | drm_warn(&i915->drm, "%s firmware %s: invalid size: %zu < %zu\n",printf("drm:pid%d:%s *WARNING* " "[drm] " "%s firmware %s: invalid size: %zu < %zu\n" , ({struct cpu_info *__ci; asm volatile("movq %%gs:%P1,%0" : "=r" (__ci) :"n" (__builtin_offsetof(struct cpu_info, ci_self))); __ci;})->ci_curproc->p_p->ps_pid, __func__ , intel_uc_fw_type_repr (uc_fw->type), uc_fw->path, fw->size, sizeof(struct uc_css_header )) | ||||
303 | intel_uc_fw_type_repr(uc_fw->type), uc_fw->path,printf("drm:pid%d:%s *WARNING* " "[drm] " "%s firmware %s: invalid size: %zu < %zu\n" , ({struct cpu_info *__ci; asm volatile("movq %%gs:%P1,%0" : "=r" (__ci) :"n" (__builtin_offsetof(struct cpu_info, ci_self))); __ci;})->ci_curproc->p_p->ps_pid, __func__ , intel_uc_fw_type_repr (uc_fw->type), uc_fw->path, fw->size, sizeof(struct uc_css_header )) | ||||
304 | fw->size, sizeof(struct uc_css_header))printf("drm:pid%d:%s *WARNING* " "[drm] " "%s firmware %s: invalid size: %zu < %zu\n" , ({struct cpu_info *__ci; asm volatile("movq %%gs:%P1,%0" : "=r" (__ci) :"n" (__builtin_offsetof(struct cpu_info, ci_self))); __ci;})->ci_curproc->p_p->ps_pid, __func__ , intel_uc_fw_type_repr (uc_fw->type), uc_fw->path, fw->size, sizeof(struct uc_css_header )); | ||||
305 | err = -ENODATA91; | ||||
306 | goto fail; | ||||
307 | } | ||||
308 | |||||
309 | css = (struct uc_css_header *)fw->data; | ||||
310 | |||||
311 | /* Check integrity of size values inside CSS header */ | ||||
312 | size = (css->header_size_dw - css->key_size_dw - css->modulus_size_dw - | ||||
313 | css->exponent_size_dw) * sizeof(u32); | ||||
314 | if (unlikely(size != sizeof(struct uc_css_header))__builtin_expect(!!(size != sizeof(struct uc_css_header)), 0)) { | ||||
315 | drm_warn(&i915->drm,printf("drm:pid%d:%s *WARNING* " "[drm] " "%s firmware %s: unexpected header size: %zu != %zu\n" , ({struct cpu_info *__ci; asm volatile("movq %%gs:%P1,%0" : "=r" (__ci) :"n" (__builtin_offsetof(struct cpu_info, ci_self))); __ci;})->ci_curproc->p_p->ps_pid, __func__ , intel_uc_fw_type_repr (uc_fw->type), uc_fw->path, fw->size, sizeof(struct uc_css_header )) | ||||
316 | "%s firmware %s: unexpected header size: %zu != %zu\n",printf("drm:pid%d:%s *WARNING* " "[drm] " "%s firmware %s: unexpected header size: %zu != %zu\n" , ({struct cpu_info *__ci; asm volatile("movq %%gs:%P1,%0" : "=r" (__ci) :"n" (__builtin_offsetof(struct cpu_info, ci_self))); __ci;})->ci_curproc->p_p->ps_pid, __func__ , intel_uc_fw_type_repr (uc_fw->type), uc_fw->path, fw->size, sizeof(struct uc_css_header )) | ||||
317 | intel_uc_fw_type_repr(uc_fw->type), uc_fw->path,printf("drm:pid%d:%s *WARNING* " "[drm] " "%s firmware %s: unexpected header size: %zu != %zu\n" , ({struct cpu_info *__ci; asm volatile("movq %%gs:%P1,%0" : "=r" (__ci) :"n" (__builtin_offsetof(struct cpu_info, ci_self))); __ci;})->ci_curproc->p_p->ps_pid, __func__ , intel_uc_fw_type_repr (uc_fw->type), uc_fw->path, fw->size, sizeof(struct uc_css_header )) | ||||
318 | fw->size, sizeof(struct uc_css_header))printf("drm:pid%d:%s *WARNING* " "[drm] " "%s firmware %s: unexpected header size: %zu != %zu\n" , ({struct cpu_info *__ci; asm volatile("movq %%gs:%P1,%0" : "=r" (__ci) :"n" (__builtin_offsetof(struct cpu_info, ci_self))); __ci;})->ci_curproc->p_p->ps_pid, __func__ , intel_uc_fw_type_repr (uc_fw->type), uc_fw->path, fw->size, sizeof(struct uc_css_header )); | ||||
319 | err = -EPROTO95; | ||||
320 | goto fail; | ||||
321 | } | ||||
322 | |||||
323 | /* uCode size must calculated from other sizes */ | ||||
324 | uc_fw->ucode_size = (css->size_dw - css->header_size_dw) * sizeof(u32); | ||||
325 | |||||
326 | /* now RSA */ | ||||
327 | if (unlikely(css->key_size_dw != UOS_RSA_SCRATCH_COUNT)__builtin_expect(!!(css->key_size_dw != 64), 0)) { | ||||
328 | drm_warn(&i915->drm, "%s firmware %s: unexpected key size: %u != %u\n",printf("drm:pid%d:%s *WARNING* " "[drm] " "%s firmware %s: unexpected key size: %u != %u\n" , ({struct cpu_info *__ci; asm volatile("movq %%gs:%P1,%0" : "=r" (__ci) :"n" (__builtin_offsetof(struct cpu_info, ci_self))); __ci;})->ci_curproc->p_p->ps_pid, __func__ , intel_uc_fw_type_repr (uc_fw->type), uc_fw->path, css->key_size_dw, 64) | ||||
329 | intel_uc_fw_type_repr(uc_fw->type), uc_fw->path,printf("drm:pid%d:%s *WARNING* " "[drm] " "%s firmware %s: unexpected key size: %u != %u\n" , ({struct cpu_info *__ci; asm volatile("movq %%gs:%P1,%0" : "=r" (__ci) :"n" (__builtin_offsetof(struct cpu_info, ci_self))); __ci;})->ci_curproc->p_p->ps_pid, __func__ , intel_uc_fw_type_repr (uc_fw->type), uc_fw->path, css->key_size_dw, 64) | ||||
330 | css->key_size_dw, UOS_RSA_SCRATCH_COUNT)printf("drm:pid%d:%s *WARNING* " "[drm] " "%s firmware %s: unexpected key size: %u != %u\n" , ({struct cpu_info *__ci; asm volatile("movq %%gs:%P1,%0" : "=r" (__ci) :"n" (__builtin_offsetof(struct cpu_info, ci_self))); __ci;})->ci_curproc->p_p->ps_pid, __func__ , intel_uc_fw_type_repr (uc_fw->type), uc_fw->path, css->key_size_dw, 64); | ||||
331 | err = -EPROTO95; | ||||
332 | goto fail; | ||||
333 | } | ||||
334 | uc_fw->rsa_size = css->key_size_dw * sizeof(u32); | ||||
335 | |||||
336 | /* At least, it should have header, uCode and RSA. Size of all three. */ | ||||
337 | size = sizeof(struct uc_css_header) + uc_fw->ucode_size + uc_fw->rsa_size; | ||||
338 | if (unlikely(fw->size < size)__builtin_expect(!!(fw->size < size), 0)) { | ||||
339 | drm_warn(&i915->drm, "%s firmware %s: invalid size: %zu < %zu\n",printf("drm:pid%d:%s *WARNING* " "[drm] " "%s firmware %s: invalid size: %zu < %zu\n" , ({struct cpu_info *__ci; asm volatile("movq %%gs:%P1,%0" : "=r" (__ci) :"n" (__builtin_offsetof(struct cpu_info, ci_self))); __ci;})->ci_curproc->p_p->ps_pid, __func__ , intel_uc_fw_type_repr (uc_fw->type), uc_fw->path, fw->size, size) | ||||
340 | intel_uc_fw_type_repr(uc_fw->type), uc_fw->path,printf("drm:pid%d:%s *WARNING* " "[drm] " "%s firmware %s: invalid size: %zu < %zu\n" , ({struct cpu_info *__ci; asm volatile("movq %%gs:%P1,%0" : "=r" (__ci) :"n" (__builtin_offsetof(struct cpu_info, ci_self))); __ci;})->ci_curproc->p_p->ps_pid, __func__ , intel_uc_fw_type_repr (uc_fw->type), uc_fw->path, fw->size, size) | ||||
341 | fw->size, size)printf("drm:pid%d:%s *WARNING* " "[drm] " "%s firmware %s: invalid size: %zu < %zu\n" , ({struct cpu_info *__ci; asm volatile("movq %%gs:%P1,%0" : "=r" (__ci) :"n" (__builtin_offsetof(struct cpu_info, ci_self))); __ci;})->ci_curproc->p_p->ps_pid, __func__ , intel_uc_fw_type_repr (uc_fw->type), uc_fw->path, fw->size, size); | ||||
342 | err = -ENOEXEC8; | ||||
343 | goto fail; | ||||
344 | } | ||||
345 | |||||
346 | /* Sanity check whether this fw is not larger than whole WOPCM memory */ | ||||
347 | size = __intel_uc_fw_get_upload_size(uc_fw); | ||||
348 | if (unlikely(size >= i915->wopcm.size)__builtin_expect(!!(size >= i915->wopcm.size), 0)) { | ||||
349 | drm_warn(&i915->drm, "%s firmware %s: invalid size: %zu > %zu\n",printf("drm:pid%d:%s *WARNING* " "[drm] " "%s firmware %s: invalid size: %zu > %zu\n" , ({struct cpu_info *__ci; asm volatile("movq %%gs:%P1,%0" : "=r" (__ci) :"n" (__builtin_offsetof(struct cpu_info, ci_self))); __ci;})->ci_curproc->p_p->ps_pid, __func__ , intel_uc_fw_type_repr (uc_fw->type), uc_fw->path, size, (size_t)i915->wopcm .size) | ||||
350 | intel_uc_fw_type_repr(uc_fw->type), uc_fw->path,printf("drm:pid%d:%s *WARNING* " "[drm] " "%s firmware %s: invalid size: %zu > %zu\n" , ({struct cpu_info *__ci; asm volatile("movq %%gs:%P1,%0" : "=r" (__ci) :"n" (__builtin_offsetof(struct cpu_info, ci_self))); __ci;})->ci_curproc->p_p->ps_pid, __func__ , intel_uc_fw_type_repr (uc_fw->type), uc_fw->path, size, (size_t)i915->wopcm .size) | ||||
351 | size, (size_t)i915->wopcm.size)printf("drm:pid%d:%s *WARNING* " "[drm] " "%s firmware %s: invalid size: %zu > %zu\n" , ({struct cpu_info *__ci; asm volatile("movq %%gs:%P1,%0" : "=r" (__ci) :"n" (__builtin_offsetof(struct cpu_info, ci_self))); __ci;})->ci_curproc->p_p->ps_pid, __func__ , intel_uc_fw_type_repr (uc_fw->type), uc_fw->path, size, (size_t)i915->wopcm .size); | ||||
352 | err = -E2BIG7; | ||||
353 | goto fail; | ||||
354 | } | ||||
355 | |||||
356 | /* Get version numbers from the CSS header */ | ||||
357 | uc_fw->major_ver_found = FIELD_GET(CSS_SW_VERSION_UC_MAJOR,((typeof((0xFF << 16)))(((css->sw_version) & ((0xFF << 16))) >> (__builtin_ffsll((0xFF << 16)) - 1))) | ||||
358 | css->sw_version)((typeof((0xFF << 16)))(((css->sw_version) & ((0xFF << 16))) >> (__builtin_ffsll((0xFF << 16)) - 1))); | ||||
359 | uc_fw->minor_ver_found = FIELD_GET(CSS_SW_VERSION_UC_MINOR,((typeof((0xFF << 8)))(((css->sw_version) & ((0xFF << 8))) >> (__builtin_ffsll((0xFF << 8)) - 1))) | ||||
360 | css->sw_version)((typeof((0xFF << 8)))(((css->sw_version) & ((0xFF << 8))) >> (__builtin_ffsll((0xFF << 8)) - 1))); | ||||
361 | |||||
362 | if (uc_fw->major_ver_found != uc_fw->major_ver_wanted || | ||||
363 | uc_fw->minor_ver_found < uc_fw->minor_ver_wanted) { | ||||
364 | drm_notice(&i915->drm, "%s firmware %s: unexpected version: %u.%u != %u.%u\n",printf("drm:pid%d:%s *NOTICE* " "[drm] " "%s firmware %s: unexpected version: %u.%u != %u.%u\n" , ({struct cpu_info *__ci; asm volatile("movq %%gs:%P1,%0" : "=r" (__ci) :"n" (__builtin_offsetof(struct cpu_info, ci_self))); __ci;})->ci_curproc->p_p->ps_pid, __func__ , intel_uc_fw_type_repr (uc_fw->type), uc_fw->path, uc_fw->major_ver_found, uc_fw ->minor_ver_found, uc_fw->major_ver_wanted, uc_fw->minor_ver_wanted ) | ||||
365 | intel_uc_fw_type_repr(uc_fw->type), uc_fw->path,printf("drm:pid%d:%s *NOTICE* " "[drm] " "%s firmware %s: unexpected version: %u.%u != %u.%u\n" , ({struct cpu_info *__ci; asm volatile("movq %%gs:%P1,%0" : "=r" (__ci) :"n" (__builtin_offsetof(struct cpu_info, ci_self))); __ci;})->ci_curproc->p_p->ps_pid, __func__ , intel_uc_fw_type_repr (uc_fw->type), uc_fw->path, uc_fw->major_ver_found, uc_fw ->minor_ver_found, uc_fw->major_ver_wanted, uc_fw->minor_ver_wanted ) | ||||
366 | uc_fw->major_ver_found, uc_fw->minor_ver_found,printf("drm:pid%d:%s *NOTICE* " "[drm] " "%s firmware %s: unexpected version: %u.%u != %u.%u\n" , ({struct cpu_info *__ci; asm volatile("movq %%gs:%P1,%0" : "=r" (__ci) :"n" (__builtin_offsetof(struct cpu_info, ci_self))); __ci;})->ci_curproc->p_p->ps_pid, __func__ , intel_uc_fw_type_repr (uc_fw->type), uc_fw->path, uc_fw->major_ver_found, uc_fw ->minor_ver_found, uc_fw->major_ver_wanted, uc_fw->minor_ver_wanted ) | ||||
367 | uc_fw->major_ver_wanted, uc_fw->minor_ver_wanted)printf("drm:pid%d:%s *NOTICE* " "[drm] " "%s firmware %s: unexpected version: %u.%u != %u.%u\n" , ({struct cpu_info *__ci; asm volatile("movq %%gs:%P1,%0" : "=r" (__ci) :"n" (__builtin_offsetof(struct cpu_info, ci_self))); __ci;})->ci_curproc->p_p->ps_pid, __func__ , intel_uc_fw_type_repr (uc_fw->type), uc_fw->path, uc_fw->major_ver_found, uc_fw ->minor_ver_found, uc_fw->major_ver_wanted, uc_fw->minor_ver_wanted ); | ||||
368 | if (!intel_uc_fw_is_overridden(uc_fw)) { | ||||
369 | err = -ENOEXEC8; | ||||
370 | goto fail; | ||||
371 | } | ||||
372 | } | ||||
373 | |||||
374 | obj = i915_gem_object_create_shmem_from_data(i915, fw->data, fw->size); | ||||
375 | if (IS_ERR(obj)) { | ||||
376 | err = PTR_ERR(obj); | ||||
377 | goto fail; | ||||
378 | } | ||||
379 | |||||
380 | uc_fw->obj = obj; | ||||
381 | uc_fw->size = fw->size; | ||||
382 | intel_uc_fw_change_status(uc_fw, INTEL_UC_FIRMWARE_AVAILABLE); | ||||
383 | |||||
384 | release_firmware(fw); | ||||
385 | return 0; | ||||
386 | |||||
387 | fail: | ||||
388 | intel_uc_fw_change_status(uc_fw, err == -ENOENT2 ? | ||||
389 | INTEL_UC_FIRMWARE_MISSING : | ||||
390 | INTEL_UC_FIRMWARE_ERROR); | ||||
391 | |||||
392 | drm_notice(&i915->drm, "%s firmware %s: fetch failed with error %d\n",printf("drm:pid%d:%s *NOTICE* " "[drm] " "%s firmware %s: fetch failed with error %d\n" , ({struct cpu_info *__ci; asm volatile("movq %%gs:%P1,%0" : "=r" (__ci) :"n" (__builtin_offsetof(struct cpu_info, ci_self))); __ci;})->ci_curproc->p_p->ps_pid, __func__ , intel_uc_fw_type_repr (uc_fw->type), uc_fw->path, err) | ||||
393 | intel_uc_fw_type_repr(uc_fw->type), uc_fw->path, err)printf("drm:pid%d:%s *NOTICE* " "[drm] " "%s firmware %s: fetch failed with error %d\n" , ({struct cpu_info *__ci; asm volatile("movq %%gs:%P1,%0" : "=r" (__ci) :"n" (__builtin_offsetof(struct cpu_info, ci_self))); __ci;})->ci_curproc->p_p->ps_pid, __func__ , intel_uc_fw_type_repr (uc_fw->type), uc_fw->path, err); | ||||
394 | #ifdef __linux__ | ||||
395 | drm_info(&i915->drm, "%s firmware(s) can be downloaded from %s\n",do { } while(0) | ||||
396 | intel_uc_fw_type_repr(uc_fw->type), INTEL_UC_FIRMWARE_URL)do { } while(0); | ||||
397 | #endif | ||||
398 | |||||
399 | release_firmware(fw); /* OK even if fw is NULL */ | ||||
400 | return err; | ||||
401 | } | ||||
402 | |||||
403 | static u32 uc_fw_ggtt_offset(struct intel_uc_fw *uc_fw) | ||||
404 | { | ||||
405 | struct i915_ggtt *ggtt = __uc_fw_to_gt(uc_fw)->ggtt; | ||||
406 | struct drm_mm_node *node = &ggtt->uc_fw; | ||||
407 | |||||
408 | GEM_BUG_ON(!drm_mm_node_allocated(node))((void)0); | ||||
409 | GEM_BUG_ON(upper_32_bits(node->start))((void)0); | ||||
410 | GEM_BUG_ON(upper_32_bits(node->start + node->size - 1))((void)0); | ||||
411 | |||||
412 | return lower_32_bits(node->start)((u32)(node->start)); | ||||
413 | } | ||||
414 | |||||
415 | static void uc_fw_bind_ggtt(struct intel_uc_fw *uc_fw) | ||||
416 | { | ||||
417 | struct drm_i915_gem_object *obj = uc_fw->obj; | ||||
418 | struct i915_ggtt *ggtt = __uc_fw_to_gt(uc_fw)->ggtt; | ||||
419 | struct i915_vma dummy = { | ||||
420 | .node.start = uc_fw_ggtt_offset(uc_fw), | ||||
421 | .node.size = obj->base.size, | ||||
422 | .pages = obj->mm.pages, | ||||
423 | .vm = &ggtt->vm, | ||||
424 | }; | ||||
425 | |||||
426 | GEM_BUG_ON(!i915_gem_object_has_pinned_pages(obj))((void)0); | ||||
427 | GEM_BUG_ON(dummy.node.size > ggtt->uc_fw.size)((void)0); | ||||
428 | |||||
429 | /* uc_fw->obj cache domains were not controlled across suspend */ | ||||
430 | drm_clflush_sg(dummy.pages); | ||||
431 | |||||
432 | ggtt->vm.insert_entries(&ggtt->vm, &dummy, I915_CACHE_NONE, 0); | ||||
433 | } | ||||
434 | |||||
435 | static void uc_fw_unbind_ggtt(struct intel_uc_fw *uc_fw) | ||||
436 | { | ||||
437 | struct drm_i915_gem_object *obj = uc_fw->obj; | ||||
438 | struct i915_ggtt *ggtt = __uc_fw_to_gt(uc_fw)->ggtt; | ||||
439 | u64 start = uc_fw_ggtt_offset(uc_fw); | ||||
440 | |||||
441 | ggtt->vm.clear_range(&ggtt->vm, start, obj->base.size); | ||||
442 | } | ||||
443 | |||||
444 | static int uc_fw_xfer(struct intel_uc_fw *uc_fw, u32 dst_offset, u32 dma_flags) | ||||
445 | { | ||||
446 | struct intel_gt *gt = __uc_fw_to_gt(uc_fw); | ||||
447 | struct intel_uncore *uncore = gt->uncore; | ||||
448 | u64 offset; | ||||
449 | int ret; | ||||
450 | |||||
451 | ret = i915_inject_probe_error(gt->i915, -ETIMEDOUT)({ ((void)0); 0; }); | ||||
452 | if (ret) | ||||
453 | return ret; | ||||
454 | |||||
455 | intel_uncore_forcewake_get(uncore, FORCEWAKE_ALL); | ||||
456 | |||||
457 | /* Set the source address for the uCode */ | ||||
458 | offset = uc_fw_ggtt_offset(uc_fw); | ||||
459 | GEM_BUG_ON(upper_32_bits(offset) & 0xFFFF0000)((void)0); | ||||
460 | intel_uncore_write_fw(uncore, DMA_ADDR_0_LOW, lower_32_bits(offset))__raw_uncore_write32(uncore, ((const i915_reg_t){ .reg = (0xc300 ) }), ((u32)(offset))); | ||||
461 | intel_uncore_write_fw(uncore, DMA_ADDR_0_HIGH, upper_32_bits(offset))__raw_uncore_write32(uncore, ((const i915_reg_t){ .reg = (0xc304 ) }), ((u32)(((offset) >> 16) >> 16))); | ||||
462 | |||||
463 | /* Set the DMA destination */ | ||||
464 | intel_uncore_write_fw(uncore, DMA_ADDR_1_LOW, dst_offset)__raw_uncore_write32(uncore, ((const i915_reg_t){ .reg = (0xc308 ) }), dst_offset); | ||||
465 | intel_uncore_write_fw(uncore, DMA_ADDR_1_HIGH, DMA_ADDRESS_SPACE_WOPCM)__raw_uncore_write32(uncore, ((const i915_reg_t){ .reg = (0xc30c ) }), (7 << 16)); | ||||
466 | |||||
467 | /* | ||||
468 | * Set the transfer size. The header plus uCode will be copied to WOPCM | ||||
469 | * via DMA, excluding any other components | ||||
470 | */ | ||||
471 | intel_uncore_write_fw(uncore, DMA_COPY_SIZE,__raw_uncore_write32(uncore, ((const i915_reg_t){ .reg = (0xc310 ) }), sizeof(struct uc_css_header) + uc_fw->ucode_size) | ||||
472 | sizeof(struct uc_css_header) + uc_fw->ucode_size)__raw_uncore_write32(uncore, ((const i915_reg_t){ .reg = (0xc310 ) }), sizeof(struct uc_css_header) + uc_fw->ucode_size); | ||||
473 | |||||
474 | /* Start the DMA */ | ||||
475 | intel_uncore_write_fw(uncore, DMA_CTRL,__raw_uncore_write32(uncore, ((const i915_reg_t){ .reg = (0xc314 ) }), ({ typeof(dma_flags | (1<<0)) _a = (dma_flags | ( 1<<0)); ({ if (__builtin_constant_p(_a)) do { } while ( 0); if (__builtin_constant_p(_a)) do { } while (0); if (__builtin_constant_p (_a) && __builtin_constant_p(_a)) do { } while (0); ( (_a) << 16 | (_a)); }); })) | ||||
476 | _MASKED_BIT_ENABLE(dma_flags | START_DMA))__raw_uncore_write32(uncore, ((const i915_reg_t){ .reg = (0xc314 ) }), ({ typeof(dma_flags | (1<<0)) _a = (dma_flags | ( 1<<0)); ({ if (__builtin_constant_p(_a)) do { } while ( 0); if (__builtin_constant_p(_a)) do { } while (0); if (__builtin_constant_p (_a) && __builtin_constant_p(_a)) do { } while (0); ( (_a) << 16 | (_a)); }); })); | ||||
477 | |||||
478 | /* Wait for DMA to finish */ | ||||
479 | ret = intel_wait_for_register_fw(uncore, DMA_CTRL((const i915_reg_t){ .reg = (0xc314) }), START_DMA(1<<0), 0, 100); | ||||
480 | if (ret) | ||||
481 | drm_err(>->i915->drm, "DMA for %s fw failed, DMA_CTRL=%u\n",printf("drm:pid%d:%s *ERROR* " "[drm] " "*ERROR* " "DMA for %s fw failed, DMA_CTRL=%u\n" , ({struct cpu_info *__ci; asm volatile("movq %%gs:%P1,%0" : "=r" (__ci) :"n" (__builtin_offsetof(struct cpu_info, ci_self))); __ci;})->ci_curproc->p_p->ps_pid, __func__ , intel_uc_fw_type_repr (uc_fw->type), __raw_uncore_read32(uncore, ((const i915_reg_t ){ .reg = (0xc314) }))) | ||||
482 | intel_uc_fw_type_repr(uc_fw->type),printf("drm:pid%d:%s *ERROR* " "[drm] " "*ERROR* " "DMA for %s fw failed, DMA_CTRL=%u\n" , ({struct cpu_info *__ci; asm volatile("movq %%gs:%P1,%0" : "=r" (__ci) :"n" (__builtin_offsetof(struct cpu_info, ci_self))); __ci;})->ci_curproc->p_p->ps_pid, __func__ , intel_uc_fw_type_repr (uc_fw->type), __raw_uncore_read32(uncore, ((const i915_reg_t ){ .reg = (0xc314) }))) | ||||
483 | intel_uncore_read_fw(uncore, DMA_CTRL))printf("drm:pid%d:%s *ERROR* " "[drm] " "*ERROR* " "DMA for %s fw failed, DMA_CTRL=%u\n" , ({struct cpu_info *__ci; asm volatile("movq %%gs:%P1,%0" : "=r" (__ci) :"n" (__builtin_offsetof(struct cpu_info, ci_self))); __ci;})->ci_curproc->p_p->ps_pid, __func__ , intel_uc_fw_type_repr (uc_fw->type), __raw_uncore_read32(uncore, ((const i915_reg_t ){ .reg = (0xc314) }))); | ||||
484 | |||||
485 | /* Disable the bits once DMA is over */ | ||||
486 | intel_uncore_write_fw(uncore, DMA_CTRL, _MASKED_BIT_DISABLE(dma_flags))__raw_uncore_write32(uncore, ((const i915_reg_t){ .reg = (0xc314 ) }), (({ if (__builtin_constant_p((dma_flags))) do { } while (0); if (__builtin_constant_p(0)) do { } while (0); if (__builtin_constant_p ((dma_flags)) && __builtin_constant_p(0)) do { } while (0); (((dma_flags)) << 16 | (0)); }))); | ||||
487 | |||||
488 | intel_uncore_forcewake_put(uncore, FORCEWAKE_ALL); | ||||
489 | |||||
490 | return ret; | ||||
491 | } | ||||
492 | |||||
493 | /** | ||||
494 | * intel_uc_fw_upload - load uC firmware using custom loader | ||||
495 | * @uc_fw: uC firmware | ||||
496 | * @dst_offset: destination offset | ||||
497 | * @dma_flags: flags for flags for dma ctrl | ||||
498 | * | ||||
499 | * Loads uC firmware and updates internal flags. | ||||
500 | * | ||||
501 | * Return: 0 on success, non-zero on failure. | ||||
502 | */ | ||||
503 | int intel_uc_fw_upload(struct intel_uc_fw *uc_fw, u32 dst_offset, u32 dma_flags) | ||||
504 | { | ||||
505 | struct intel_gt *gt = __uc_fw_to_gt(uc_fw); | ||||
506 | int err; | ||||
507 | |||||
508 | /* make sure the status was cleared the last time we reset the uc */ | ||||
509 | GEM_BUG_ON(intel_uc_fw_is_loaded(uc_fw))((void)0); | ||||
510 | |||||
511 | err = i915_inject_probe_error(gt->i915, -ENOEXEC)({ ((void)0); 0; }); | ||||
512 | if (err) | ||||
513 | return err; | ||||
514 | |||||
515 | if (!intel_uc_fw_is_loadable(uc_fw)) | ||||
516 | return -ENOEXEC8; | ||||
517 | |||||
518 | /* Call custom loader */ | ||||
519 | uc_fw_bind_ggtt(uc_fw); | ||||
520 | err = uc_fw_xfer(uc_fw, dst_offset, dma_flags); | ||||
521 | uc_fw_unbind_ggtt(uc_fw); | ||||
522 | if (err) | ||||
523 | goto fail; | ||||
524 | |||||
525 | intel_uc_fw_change_status(uc_fw, INTEL_UC_FIRMWARE_TRANSFERRED); | ||||
526 | return 0; | ||||
527 | |||||
528 | fail: | ||||
529 | i915_probe_error(gt->i915, "Failed to load %s firmware %s (%d)\n",__i915_printk(gt->i915, 0 ? "\0017" : "\0013", "Failed to load %s firmware %s (%d)\n" , intel_uc_fw_type_repr(uc_fw->type), uc_fw->path, err) | ||||
530 | intel_uc_fw_type_repr(uc_fw->type), uc_fw->path,__i915_printk(gt->i915, 0 ? "\0017" : "\0013", "Failed to load %s firmware %s (%d)\n" , intel_uc_fw_type_repr(uc_fw->type), uc_fw->path, err) | ||||
531 | err)__i915_printk(gt->i915, 0 ? "\0017" : "\0013", "Failed to load %s firmware %s (%d)\n" , intel_uc_fw_type_repr(uc_fw->type), uc_fw->path, err); | ||||
532 | intel_uc_fw_change_status(uc_fw, INTEL_UC_FIRMWARE_FAIL); | ||||
533 | return err; | ||||
534 | } | ||||
535 | |||||
536 | int intel_uc_fw_init(struct intel_uc_fw *uc_fw) | ||||
537 | { | ||||
538 | int err; | ||||
539 | |||||
540 | /* this should happen before the load! */ | ||||
541 | GEM_BUG_ON(intel_uc_fw_is_loaded(uc_fw))((void)0); | ||||
542 | |||||
543 | if (!intel_uc_fw_is_available(uc_fw)) | ||||
544 | return -ENOEXEC8; | ||||
545 | |||||
546 | err = i915_gem_object_pin_pages(uc_fw->obj); | ||||
547 | if (err) { | ||||
548 | DRM_DEBUG_DRIVER("%s fw pin-pages err=%d\n",__drm_dbg(DRM_UT_DRIVER, "%s fw pin-pages err=%d\n", intel_uc_fw_type_repr (uc_fw->type), err) | ||||
549 | intel_uc_fw_type_repr(uc_fw->type), err)__drm_dbg(DRM_UT_DRIVER, "%s fw pin-pages err=%d\n", intel_uc_fw_type_repr (uc_fw->type), err); | ||||
550 | intel_uc_fw_change_status(uc_fw, INTEL_UC_FIRMWARE_FAIL); | ||||
551 | } | ||||
552 | |||||
553 | return err; | ||||
554 | } | ||||
555 | |||||
556 | void intel_uc_fw_fini(struct intel_uc_fw *uc_fw) | ||||
557 | { | ||||
558 | if (i915_gem_object_has_pinned_pages(uc_fw->obj)) | ||||
559 | i915_gem_object_unpin_pages(uc_fw->obj); | ||||
560 | |||||
561 | intel_uc_fw_change_status(uc_fw, INTEL_UC_FIRMWARE_AVAILABLE); | ||||
562 | } | ||||
563 | |||||
564 | /** | ||||
565 | * intel_uc_fw_cleanup_fetch - cleanup uC firmware | ||||
566 | * @uc_fw: uC firmware | ||||
567 | * | ||||
568 | * Cleans up uC firmware by releasing the firmware GEM obj. | ||||
569 | */ | ||||
570 | void intel_uc_fw_cleanup_fetch(struct intel_uc_fw *uc_fw) | ||||
571 | { | ||||
572 | if (!intel_uc_fw_is_available(uc_fw)) | ||||
573 | return; | ||||
574 | |||||
575 | i915_gem_object_put(fetch_and_zero(&uc_fw->obj)({ typeof(*&uc_fw->obj) __T = *(&uc_fw->obj); * (&uc_fw->obj) = (typeof(*&uc_fw->obj))0; __T; } )); | ||||
576 | |||||
577 | intel_uc_fw_change_status(uc_fw, INTEL_UC_FIRMWARE_SELECTED); | ||||
578 | } | ||||
579 | |||||
580 | /** | ||||
581 | * intel_uc_fw_copy_rsa - copy fw RSA to buffer | ||||
582 | * | ||||
583 | * @uc_fw: uC firmware | ||||
584 | * @dst: dst buffer | ||||
585 | * @max_len: max number of bytes to copy | ||||
586 | * | ||||
587 | * Return: number of copied bytes. | ||||
588 | */ | ||||
589 | size_t intel_uc_fw_copy_rsa(struct intel_uc_fw *uc_fw, void *dst, u32 max_len) | ||||
590 | { | ||||
591 | STUB()do { printf("%s: stub\n", __func__); } while(0); | ||||
592 | return 0; | ||||
593 | #ifdef notyet | ||||
594 | struct sg_table *pages = uc_fw->obj->mm.pages; | ||||
595 | u32 size = min_t(u32, uc_fw->rsa_size, max_len)({ u32 __min_a = (uc_fw->rsa_size); u32 __min_b = (max_len ); __min_a < __min_b ? __min_a : __min_b; }); | ||||
596 | u32 offset = sizeof(struct uc_css_header) + uc_fw->ucode_size; | ||||
597 | |||||
598 | GEM_BUG_ON(!intel_uc_fw_is_available(uc_fw))((void)0); | ||||
599 | |||||
600 | return sg_pcopy_to_buffer(pages->sgl, pages->nents, dst, size, offset); | ||||
601 | #endif | ||||
602 | } | ||||
603 | |||||
604 | /** | ||||
605 | * intel_uc_fw_dump - dump information about uC firmware | ||||
606 | * @uc_fw: uC firmware | ||||
607 | * @p: the &drm_printer | ||||
608 | * | ||||
609 | * Pretty printer for uC firmware. | ||||
610 | */ | ||||
611 | void intel_uc_fw_dump(const struct intel_uc_fw *uc_fw, struct drm_printer *p) | ||||
612 | { | ||||
613 | drm_printf(p, "%s firmware: %s\n", | ||||
614 | intel_uc_fw_type_repr(uc_fw->type), uc_fw->path); | ||||
615 | drm_printf(p, "\tstatus: %s\n", | ||||
616 | intel_uc_fw_status_repr(uc_fw->status)); | ||||
617 | drm_printf(p, "\tversion: wanted %u.%u, found %u.%u\n", | ||||
618 | uc_fw->major_ver_wanted, uc_fw->minor_ver_wanted, | ||||
619 | uc_fw->major_ver_found, uc_fw->minor_ver_found); | ||||
620 | drm_printf(p, "\tuCode: %u bytes\n", uc_fw->ucode_size); | ||||
621 | drm_printf(p, "\tRSA: %u bytes\n", uc_fw->rsa_size); | ||||
622 | } |
1 | /* Public domain. */ |
2 | |
3 | #ifndef _LINUX_FIRMWARE_H |
4 | #define _LINUX_FIRMWARE_H |
5 | |
6 | #include <sys/types.h> |
7 | #include <sys/malloc.h> |
8 | #include <sys/device.h> |
9 | #include <linux/types.h> |
10 | #include <linux/gfp.h> |
11 | |
12 | #ifndef __DECONST |
13 | #define __DECONST(type, var)((type)(__uintptr_t)(const void *)(var)) ((type)(__uintptr_t)(const void *)(var)) |
14 | #endif |
15 | |
16 | struct firmware { |
17 | size_t size; |
18 | const u8 *data; |
19 | }; |
20 | |
21 | static inline int |
22 | request_firmware(const struct firmware **fw, const char *name, |
23 | struct device *device) |
24 | { |
25 | int r; |
26 | struct firmware *f = malloc(sizeof(struct firmware), M_DRM145, |
27 | M_WAITOK0x0001 | M_ZERO0x0008); |
28 | r = loadfirmware(name, __DECONST(u_char **, &f->data)((u_char **)(__uintptr_t)(const void *)(&f->data)), &f->size); |
29 | if (r != 0) { |
30 | free(f, M_DRM145, sizeof(struct firmware)); |
31 | *fw = NULL((void *)0); |
32 | return -r; |
33 | } else { |
34 | *fw = f; |
35 | return 0; |
36 | } |
37 | } |
38 | |
39 | static inline int |
40 | request_firmware_direct(const struct firmware **fw, const char *name, |
41 | struct device *device) |
42 | { |
43 | return request_firmware(fw, name, device); |
44 | } |
45 | |
46 | #define request_firmware_nowait(a, b, c, d, e, f, g)-22 -EINVAL22 |
47 | |
48 | static inline void |
49 | release_firmware(const struct firmware *fw) |
50 | { |
51 | if (fw) |
52 | free(__DECONST(u_char *, fw->data)((u_char *)(__uintptr_t)(const void *)(fw->data)), M_DEVBUF2, fw->size); |
53 | free(__DECONST(struct firmware *, fw)((struct firmware *)(__uintptr_t)(const void *)(fw)), M_DRM145, sizeof(*fw)); |
54 | } |
55 | |
56 | #endif |