| 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 |