1dd08ebf6SMatthew Brost // SPDX-License-Identifier: MIT 2dd08ebf6SMatthew Brost /* 3dd08ebf6SMatthew Brost * Copyright © 2022 Intel Corporation 4dd08ebf6SMatthew Brost */ 5dd08ebf6SMatthew Brost 6dd08ebf6SMatthew Brost #include <linux/bitfield.h> 7dd08ebf6SMatthew Brost #include <linux/firmware.h> 8dd08ebf6SMatthew Brost 9dd08ebf6SMatthew Brost #include <drm/drm_managed.h> 10dd08ebf6SMatthew Brost 11a9b1a136SLucas De Marchi #include "regs/xe_guc_regs.h" 12dd08ebf6SMatthew Brost #include "xe_bo.h" 13dd08ebf6SMatthew Brost #include "xe_device_types.h" 14dd08ebf6SMatthew Brost #include "xe_force_wake.h" 15985d5a49SDaniele Ceraolo Spurio #include "xe_gsc.h" 16dd08ebf6SMatthew Brost #include "xe_gt.h" 1726a22952SMichal Wajdeczko #include "xe_gt_printk.h" 184eb0aab6SJulia Filipchuk #include "xe_guc.h" 19dd08ebf6SMatthew Brost #include "xe_map.h" 20dd08ebf6SMatthew Brost #include "xe_mmio.h" 21a455ed04SDaniele Ceraolo Spurio #include "xe_module.h" 2266cb3ca9SMichal Wajdeczko #include "xe_sriov.h" 23dd08ebf6SMatthew Brost #include "xe_uc_fw.h" 24dd08ebf6SMatthew Brost 25ad55ead7SLucas De Marchi /* 26ad55ead7SLucas De Marchi * List of required GuC and HuC binaries per-platform. They must be ordered 27ad55ead7SLucas De Marchi * based on platform, from newer to older. 28ad55ead7SLucas De Marchi * 29ad55ead7SLucas De Marchi * Versioning follows the guidelines from 30ad55ead7SLucas De Marchi * Documentation/driver-api/firmware/firmware-usage-guidelines.rst. There is a 31ad55ead7SLucas De Marchi * distinction for platforms being officially supported by the driver or not. 32ad55ead7SLucas De Marchi * Platforms not available publicly or not yet officially supported by the 33ad55ead7SLucas De Marchi * driver (under force-probe), use the mmp_ver(): the firmware autoselect logic 34ad55ead7SLucas De Marchi * will select the firmware from disk with filename that matches the full 35ad55ead7SLucas De Marchi * "mpp version", i.e. major.minor.patch. mmp_ver() should only be used for 36ad55ead7SLucas De Marchi * this case. 37ad55ead7SLucas De Marchi * 38ad55ead7SLucas De Marchi * For platforms officially supported by the driver, the filename always only 39ad55ead7SLucas De Marchi * ever contains the major version (GuC) or no version at all (HuC). 40ad55ead7SLucas De Marchi * 41ad55ead7SLucas De Marchi * After loading the file, the driver parses the versions embedded in the blob. 42ad55ead7SLucas De Marchi * The major version needs to match a major version supported by the driver (if 43ad55ead7SLucas De Marchi * any). The minor version is also checked and a notice emitted to the log if 44ad55ead7SLucas De Marchi * the version found is smaller than the version wanted. This is done only for 45ad55ead7SLucas De Marchi * informational purposes so users may have a chance to upgrade, but the driver 46ad55ead7SLucas De Marchi * still loads and use the older firmware. 47ad55ead7SLucas De Marchi * 48ad55ead7SLucas De Marchi * Examples: 49ad55ead7SLucas De Marchi * 50ad55ead7SLucas De Marchi * 1) Platform officially supported by i915 - using Tigerlake as example. 51ad55ead7SLucas De Marchi * Driver loads the following firmware blobs from disk: 52ad55ead7SLucas De Marchi * 53ad55ead7SLucas De Marchi * - i915/tgl_guc_<major>.bin 54ad55ead7SLucas De Marchi * - i915/tgl_huc.bin 55ad55ead7SLucas De Marchi * 56ad55ead7SLucas De Marchi * <major> number for GuC is checked that it matches the version inside 57ad55ead7SLucas De Marchi * the blob. <minor> version is checked and if smaller than the expected 58ad55ead7SLucas De Marchi * an info message is emitted about that. 59ad55ead7SLucas De Marchi * 60ad55ead7SLucas De Marchi * 1) XE_<FUTUREINTELPLATFORM>, still under require_force_probe. Using 61ad55ead7SLucas De Marchi * "wipplat" as a short-name. Driver loads the following firmware blobs 62ad55ead7SLucas De Marchi * from disk: 63ad55ead7SLucas De Marchi * 64ad55ead7SLucas De Marchi * - xe/wipplat_guc_<major>.<minor>.<patch>.bin 65ad55ead7SLucas De Marchi * - xe/wipplat_huc_<major>.<minor>.<patch>.bin 66ad55ead7SLucas De Marchi * 67ad55ead7SLucas De Marchi * <major> and <minor> are checked that they match the version inside 68ad55ead7SLucas De Marchi * the blob. Both of them need to match exactly what the driver is 69ad55ead7SLucas De Marchi * expecting, otherwise it fails. 70ad55ead7SLucas De Marchi * 71ad55ead7SLucas De Marchi * 3) Platform officially supported by xe and out of force-probe. Using 72ad55ead7SLucas De Marchi * "plat" as a short-name. Except for the different directory, the 73ad55ead7SLucas De Marchi * behavior is the same as (1). Driver loads the following firmware 74ad55ead7SLucas De Marchi * blobs from disk: 75ad55ead7SLucas De Marchi * 76ad55ead7SLucas De Marchi * - xe/plat_guc_<major>.bin 77ad55ead7SLucas De Marchi * - xe/plat_huc.bin 78ad55ead7SLucas De Marchi * 79ad55ead7SLucas De Marchi * <major> number for GuC is checked that it matches the version inside 80ad55ead7SLucas De Marchi * the blob. <minor> version is checked and if smaller than the expected 81ad55ead7SLucas De Marchi * an info message is emitted about that. 82ad55ead7SLucas De Marchi * 83ad55ead7SLucas De Marchi * For the platforms already released with a major version, they should never be 84ad55ead7SLucas De Marchi * removed from the table. Instead new entries with newer versions may be added 85ad55ead7SLucas De Marchi * before them, so they take precedence. 86ad55ead7SLucas De Marchi * 87ad55ead7SLucas De Marchi * TODO: Currently there's no fallback on major version. That's because xe 88ad55ead7SLucas De Marchi * driver only supports the one major version of each firmware in the table. 89ad55ead7SLucas De Marchi * This needs to be fixed when the major version of GuC is updated. 90ad55ead7SLucas De Marchi */ 91ad55ead7SLucas De Marchi 92ad55ead7SLucas De Marchi struct uc_fw_entry { 93ad55ead7SLucas De Marchi enum xe_platform platform; 94ad55ead7SLucas De Marchi struct { 95ad55ead7SLucas De Marchi const char *path; 96ad55ead7SLucas De Marchi u16 major; 97ad55ead7SLucas De Marchi u16 minor; 986650ad3eSJohn Harrison u16 patch; 99ad55ead7SLucas De Marchi bool full_ver_required; 100ad55ead7SLucas De Marchi }; 101ad55ead7SLucas De Marchi }; 102ad55ead7SLucas De Marchi 103ad55ead7SLucas De Marchi struct fw_blobs_by_type { 104ad55ead7SLucas De Marchi const struct uc_fw_entry *entries; 105ad55ead7SLucas De Marchi u32 count; 106ad55ead7SLucas De Marchi }; 107ad55ead7SLucas De Marchi 108ad55ead7SLucas De Marchi #define XE_GUC_FIRMWARE_DEFS(fw_def, mmp_ver, major_ver) \ 1099cc033e0SJulia Filipchuk fw_def(BATTLEMAGE, major_ver(xe, guc, bmg, 70, 29, 2)) \ 1104eb0aab6SJulia Filipchuk fw_def(LUNARLAKE, major_ver(xe, guc, lnl, 70, 29, 2)) \ 1114eb0aab6SJulia Filipchuk fw_def(METEORLAKE, major_ver(i915, guc, mtl, 70, 29, 2)) \ 1124eb0aab6SJulia Filipchuk fw_def(DG2, major_ver(i915, guc, dg2, 70, 29, 2)) \ 1134eb0aab6SJulia Filipchuk fw_def(DG1, major_ver(i915, guc, dg1, 70, 29, 2)) \ 1144eb0aab6SJulia Filipchuk fw_def(ALDERLAKE_N, major_ver(i915, guc, tgl, 70, 29, 2)) \ 1154eb0aab6SJulia Filipchuk fw_def(ALDERLAKE_P, major_ver(i915, guc, adlp, 70, 29, 2)) \ 1164eb0aab6SJulia Filipchuk fw_def(ALDERLAKE_S, major_ver(i915, guc, tgl, 70, 29, 2)) \ 1174eb0aab6SJulia Filipchuk fw_def(ROCKETLAKE, major_ver(i915, guc, tgl, 70, 29, 2)) \ 1184eb0aab6SJulia Filipchuk fw_def(TIGERLAKE, major_ver(i915, guc, tgl, 70, 29, 2)) 119ad55ead7SLucas De Marchi 120ad55ead7SLucas De Marchi #define XE_HUC_FIRMWARE_DEFS(fw_def, mmp_ver, no_ver) \ 121351a8871SDaniele Ceraolo Spurio fw_def(BATTLEMAGE, no_ver(xe, huc, bmg)) \ 122e8149028SDaniele Ceraolo Spurio fw_def(LUNARLAKE, no_ver(xe, huc, lnl)) \ 123bfeb4ac5SDaniele Ceraolo Spurio fw_def(METEORLAKE, no_ver(i915, huc_gsc, mtl)) \ 124420c6a6fSDaniele Ceraolo Spurio fw_def(DG1, no_ver(i915, huc, dg1)) \ 12585635f5dSLucas De Marchi fw_def(ALDERLAKE_P, no_ver(i915, huc, tgl)) \ 126ad55ead7SLucas De Marchi fw_def(ALDERLAKE_S, no_ver(i915, huc, tgl)) \ 12794324e6bSAnusha Srivatsa fw_def(ROCKETLAKE, no_ver(i915, huc, tgl)) \ 128ad55ead7SLucas De Marchi fw_def(TIGERLAKE, no_ver(i915, huc, tgl)) 129ad55ead7SLucas De Marchi 1305152234eSDaniele Ceraolo Spurio /* for the GSC FW we match the compatibility version and not the release one */ 1315152234eSDaniele Ceraolo Spurio #define XE_GSC_FIRMWARE_DEFS(fw_def, major_ver) \ 132*f7c2ea68SDaniele Ceraolo Spurio fw_def(LUNARLAKE, major_ver(xe, gsc, lnl, 104, 1, 0)) \ 133*f7c2ea68SDaniele Ceraolo Spurio fw_def(METEORLAKE, major_ver(i915, gsc, mtl, 102, 1, 0)) 1345152234eSDaniele Ceraolo Spurio 135ad55ead7SLucas De Marchi #define MAKE_FW_PATH(dir__, uc__, shortname__, version__) \ 136ad55ead7SLucas De Marchi __stringify(dir__) "/" __stringify(shortname__) "_" __stringify(uc__) version__ ".bin" 137ad55ead7SLucas De Marchi 138ad55ead7SLucas De Marchi #define fw_filename_mmp_ver(dir_, uc_, shortname_, a, b, c) \ 139ad55ead7SLucas De Marchi MAKE_FW_PATH(dir_, uc_, shortname_, "_" __stringify(a ## . ## b ## . ## c)) 1406650ad3eSJohn Harrison #define fw_filename_major_ver(dir_, uc_, shortname_, a, b, c) \ 141ad55ead7SLucas De Marchi MAKE_FW_PATH(dir_, uc_, shortname_, "_" __stringify(a)) 142ad55ead7SLucas De Marchi #define fw_filename_no_ver(dir_, uc_, shortname_) \ 143ad55ead7SLucas De Marchi MAKE_FW_PATH(dir_, uc_, shortname_, "") 144*f7c2ea68SDaniele Ceraolo Spurio #define fw_filename_gsc(dir_, uc_, shortname_, a, b, c) \ 145*f7c2ea68SDaniele Ceraolo Spurio MAKE_FW_PATH(dir_, uc_, shortname_, "_" __stringify(b)) 146ad55ead7SLucas De Marchi 147ad55ead7SLucas De Marchi #define uc_fw_entry_mmp_ver(dir_, uc_, shortname_, a, b, c) \ 148ad55ead7SLucas De Marchi { fw_filename_mmp_ver(dir_, uc_, shortname_, a, b, c), \ 1496650ad3eSJohn Harrison a, b, c, true } 1506650ad3eSJohn Harrison #define uc_fw_entry_major_ver(dir_, uc_, shortname_, a, b, c) \ 1516650ad3eSJohn Harrison { fw_filename_major_ver(dir_, uc_, shortname_, a, b, c), \ 1526650ad3eSJohn Harrison a, b, c } 153ad55ead7SLucas De Marchi #define uc_fw_entry_no_ver(dir_, uc_, shortname_) \ 154ad55ead7SLucas De Marchi { fw_filename_no_ver(dir_, uc_, shortname_), \ 155ad55ead7SLucas De Marchi 0, 0 } 156*f7c2ea68SDaniele Ceraolo Spurio #define uc_fw_entry_gsc(dir_, uc_, shortname_, a, b, c) \ 157*f7c2ea68SDaniele Ceraolo Spurio { fw_filename_gsc(dir_, uc_, shortname_, a, b, c), \ 158*f7c2ea68SDaniele Ceraolo Spurio a, b, c } 159ad55ead7SLucas De Marchi 160ad55ead7SLucas De Marchi /* All blobs need to be declared via MODULE_FIRMWARE() */ 161ad55ead7SLucas De Marchi #define XE_UC_MODULE_FIRMWARE(platform__, fw_filename) \ 162ad55ead7SLucas De Marchi MODULE_FIRMWARE(fw_filename); 163ad55ead7SLucas De Marchi 164ad55ead7SLucas De Marchi #define XE_UC_FW_ENTRY(platform__, entry__) \ 165ad55ead7SLucas De Marchi { \ 166ad55ead7SLucas De Marchi .platform = XE_ ## platform__, \ 167ad55ead7SLucas De Marchi entry__, \ 168ad55ead7SLucas De Marchi }, 169ad55ead7SLucas De Marchi 1703e8e7ee6SFrancois Dugast XE_GUC_FIRMWARE_DEFS(XE_UC_MODULE_FIRMWARE, 171ad55ead7SLucas De Marchi fw_filename_mmp_ver, fw_filename_major_ver) 1723e8e7ee6SFrancois Dugast XE_HUC_FIRMWARE_DEFS(XE_UC_MODULE_FIRMWARE, 173ad55ead7SLucas De Marchi fw_filename_mmp_ver, fw_filename_no_ver) 174*f7c2ea68SDaniele Ceraolo Spurio XE_GSC_FIRMWARE_DEFS(XE_UC_MODULE_FIRMWARE, fw_filename_gsc) 175ad55ead7SLucas De Marchi 176dd08ebf6SMatthew Brost static struct xe_gt * 177dd08ebf6SMatthew Brost __uc_fw_to_gt(struct xe_uc_fw *uc_fw, enum xe_uc_fw_type type) 178dd08ebf6SMatthew Brost { 1790d1caff4SDaniele Ceraolo Spurio XE_WARN_ON(type >= XE_UC_FW_NUM_TYPES); 180dd08ebf6SMatthew Brost 1810d1caff4SDaniele Ceraolo Spurio switch (type) { 1820d1caff4SDaniele Ceraolo Spurio case XE_UC_FW_TYPE_GUC: 1830d1caff4SDaniele Ceraolo Spurio return container_of(uc_fw, struct xe_gt, uc.guc.fw); 1840d1caff4SDaniele Ceraolo Spurio case XE_UC_FW_TYPE_HUC: 185dd08ebf6SMatthew Brost return container_of(uc_fw, struct xe_gt, uc.huc.fw); 1860d1caff4SDaniele Ceraolo Spurio case XE_UC_FW_TYPE_GSC: 1870d1caff4SDaniele Ceraolo Spurio return container_of(uc_fw, struct xe_gt, uc.gsc.fw); 1880d1caff4SDaniele Ceraolo Spurio default: 1890d1caff4SDaniele Ceraolo Spurio return NULL; 1900d1caff4SDaniele Ceraolo Spurio } 191dd08ebf6SMatthew Brost } 192dd08ebf6SMatthew Brost 193dd08ebf6SMatthew Brost static struct xe_gt *uc_fw_to_gt(struct xe_uc_fw *uc_fw) 194dd08ebf6SMatthew Brost { 195dd08ebf6SMatthew Brost return __uc_fw_to_gt(uc_fw, uc_fw->type); 196dd08ebf6SMatthew Brost } 197dd08ebf6SMatthew Brost 198dd08ebf6SMatthew Brost static struct xe_device *uc_fw_to_xe(struct xe_uc_fw *uc_fw) 199dd08ebf6SMatthew Brost { 200dd08ebf6SMatthew Brost return gt_to_xe(uc_fw_to_gt(uc_fw)); 201dd08ebf6SMatthew Brost } 202dd08ebf6SMatthew Brost 203dd08ebf6SMatthew Brost static void 204dd08ebf6SMatthew Brost uc_fw_auto_select(struct xe_device *xe, struct xe_uc_fw *uc_fw) 205dd08ebf6SMatthew Brost { 206ad55ead7SLucas De Marchi static const struct uc_fw_entry entries_guc[] = { 207ad55ead7SLucas De Marchi XE_GUC_FIRMWARE_DEFS(XE_UC_FW_ENTRY, 208ad55ead7SLucas De Marchi uc_fw_entry_mmp_ver, 209ad55ead7SLucas De Marchi uc_fw_entry_major_ver) 210dd08ebf6SMatthew Brost }; 211ad55ead7SLucas De Marchi static const struct uc_fw_entry entries_huc[] = { 212ad55ead7SLucas De Marchi XE_HUC_FIRMWARE_DEFS(XE_UC_FW_ENTRY, 213ad55ead7SLucas De Marchi uc_fw_entry_mmp_ver, 214ad55ead7SLucas De Marchi uc_fw_entry_no_ver) 215dd08ebf6SMatthew Brost }; 2165152234eSDaniele Ceraolo Spurio static const struct uc_fw_entry entries_gsc[] = { 217*f7c2ea68SDaniele Ceraolo Spurio XE_GSC_FIRMWARE_DEFS(XE_UC_FW_ENTRY, uc_fw_entry_gsc) 2185152234eSDaniele Ceraolo Spurio }; 219dd08ebf6SMatthew Brost static const struct fw_blobs_by_type blobs_all[XE_UC_FW_NUM_TYPES] = { 220ad55ead7SLucas De Marchi [XE_UC_FW_TYPE_GUC] = { entries_guc, ARRAY_SIZE(entries_guc) }, 221ad55ead7SLucas De Marchi [XE_UC_FW_TYPE_HUC] = { entries_huc, ARRAY_SIZE(entries_huc) }, 2225152234eSDaniele Ceraolo Spurio [XE_UC_FW_TYPE_GSC] = { entries_gsc, ARRAY_SIZE(entries_gsc) }, 223dd08ebf6SMatthew Brost }; 224ad55ead7SLucas De Marchi static const struct uc_fw_entry *entries; 225dd08ebf6SMatthew Brost enum xe_platform p = xe->info.platform; 226ad55ead7SLucas De Marchi u32 count; 227dd08ebf6SMatthew Brost int i; 228dd08ebf6SMatthew Brost 229c73acc1eSFrancois Dugast xe_assert(xe, uc_fw->type < ARRAY_SIZE(blobs_all)); 230ad55ead7SLucas De Marchi entries = blobs_all[uc_fw->type].entries; 231ad55ead7SLucas De Marchi count = blobs_all[uc_fw->type].count; 232dd08ebf6SMatthew Brost 233ad55ead7SLucas De Marchi for (i = 0; i < count && p <= entries[i].platform; i++) { 234ad55ead7SLucas De Marchi if (p == entries[i].platform) { 235ad55ead7SLucas De Marchi uc_fw->path = entries[i].path; 2362e7227b4SDaniele Ceraolo Spurio uc_fw->versions.wanted.major = entries[i].major; 2372e7227b4SDaniele Ceraolo Spurio uc_fw->versions.wanted.minor = entries[i].minor; 2386650ad3eSJohn Harrison uc_fw->versions.wanted.patch = entries[i].patch; 239ad55ead7SLucas De Marchi uc_fw->full_ver_required = entries[i].full_ver_required; 2402e7227b4SDaniele Ceraolo Spurio 2410881cbe0SDaniele Ceraolo Spurio if (uc_fw->type == XE_UC_FW_TYPE_GSC) 2420881cbe0SDaniele Ceraolo Spurio uc_fw->versions.wanted_type = XE_UC_FW_VER_COMPATIBILITY; 2430881cbe0SDaniele Ceraolo Spurio else 2442e7227b4SDaniele Ceraolo Spurio uc_fw->versions.wanted_type = XE_UC_FW_VER_RELEASE; 2450881cbe0SDaniele Ceraolo Spurio 246dd08ebf6SMatthew Brost break; 247dd08ebf6SMatthew Brost } 248dd08ebf6SMatthew Brost } 249dd08ebf6SMatthew Brost } 250dd08ebf6SMatthew Brost 251a455ed04SDaniele Ceraolo Spurio static void 252a455ed04SDaniele Ceraolo Spurio uc_fw_override(struct xe_uc_fw *uc_fw) 253a455ed04SDaniele Ceraolo Spurio { 254a455ed04SDaniele Ceraolo Spurio char *path_override = NULL; 255a455ed04SDaniele Ceraolo Spurio 256a455ed04SDaniele Ceraolo Spurio /* empty string disables, but it's not allowed for GuC */ 257a455ed04SDaniele Ceraolo Spurio switch (uc_fw->type) { 258a455ed04SDaniele Ceraolo Spurio case XE_UC_FW_TYPE_GUC: 259adce1b39SBommithi Sakeena if (xe_modparam.guc_firmware_path && *xe_modparam.guc_firmware_path) 260adce1b39SBommithi Sakeena path_override = xe_modparam.guc_firmware_path; 261a455ed04SDaniele Ceraolo Spurio break; 262a455ed04SDaniele Ceraolo Spurio case XE_UC_FW_TYPE_HUC: 263adce1b39SBommithi Sakeena path_override = xe_modparam.huc_firmware_path; 264a455ed04SDaniele Ceraolo Spurio break; 2655152234eSDaniele Ceraolo Spurio case XE_UC_FW_TYPE_GSC: 2665152234eSDaniele Ceraolo Spurio path_override = xe_modparam.gsc_firmware_path; 2675152234eSDaniele Ceraolo Spurio break; 268a455ed04SDaniele Ceraolo Spurio default: 269a455ed04SDaniele Ceraolo Spurio break; 270a455ed04SDaniele Ceraolo Spurio } 271a455ed04SDaniele Ceraolo Spurio 272a455ed04SDaniele Ceraolo Spurio if (path_override) { 273a455ed04SDaniele Ceraolo Spurio uc_fw->path = path_override; 274a455ed04SDaniele Ceraolo Spurio uc_fw->user_overridden = true; 275a455ed04SDaniele Ceraolo Spurio } 276a455ed04SDaniele Ceraolo Spurio } 277a455ed04SDaniele Ceraolo Spurio 278dd08ebf6SMatthew Brost /** 279dd08ebf6SMatthew Brost * xe_uc_fw_copy_rsa - copy fw RSA to buffer 280dd08ebf6SMatthew Brost * 281dd08ebf6SMatthew Brost * @uc_fw: uC firmware 282dd08ebf6SMatthew Brost * @dst: dst buffer 283dd08ebf6SMatthew Brost * @max_len: max number of bytes to copy 284dd08ebf6SMatthew Brost * 285dd08ebf6SMatthew Brost * Return: number of copied bytes. 286dd08ebf6SMatthew Brost */ 287dd08ebf6SMatthew Brost size_t xe_uc_fw_copy_rsa(struct xe_uc_fw *uc_fw, void *dst, u32 max_len) 288dd08ebf6SMatthew Brost { 289dd08ebf6SMatthew Brost struct xe_device *xe = uc_fw_to_xe(uc_fw); 290dd08ebf6SMatthew Brost u32 size = min_t(u32, uc_fw->rsa_size, max_len); 291dd08ebf6SMatthew Brost 292c73acc1eSFrancois Dugast xe_assert(xe, !(size % 4)); 293c73acc1eSFrancois Dugast xe_assert(xe, xe_uc_fw_is_available(uc_fw)); 294dd08ebf6SMatthew Brost 295dd08ebf6SMatthew Brost xe_map_memcpy_from(xe, dst, &uc_fw->bo->vmap, 296dd08ebf6SMatthew Brost xe_uc_fw_rsa_offset(uc_fw), size); 297dd08ebf6SMatthew Brost 298dd08ebf6SMatthew Brost return size; 299dd08ebf6SMatthew Brost } 300dd08ebf6SMatthew Brost 301dd08ebf6SMatthew Brost static void uc_fw_fini(struct drm_device *drm, void *arg) 302dd08ebf6SMatthew Brost { 303dd08ebf6SMatthew Brost struct xe_uc_fw *uc_fw = arg; 304dd08ebf6SMatthew Brost 305dd08ebf6SMatthew Brost if (!xe_uc_fw_is_available(uc_fw)) 306dd08ebf6SMatthew Brost return; 307dd08ebf6SMatthew Brost 308dd08ebf6SMatthew Brost xe_uc_fw_change_status(uc_fw, XE_UC_FIRMWARE_SELECTED); 309dd08ebf6SMatthew Brost } 310dd08ebf6SMatthew Brost 31143c4ff3cSDaniele Ceraolo Spurio static int guc_read_css_info(struct xe_uc_fw *uc_fw, struct uc_css_header *css) 31299c821b0SMatthew Brost { 31399c821b0SMatthew Brost struct xe_gt *gt = uc_fw_to_gt(uc_fw); 3142e7227b4SDaniele Ceraolo Spurio struct xe_uc_fw_version *release = &uc_fw->versions.found[XE_UC_FW_VER_RELEASE]; 3152e7227b4SDaniele Ceraolo Spurio struct xe_uc_fw_version *compatibility = &uc_fw->versions.found[XE_UC_FW_VER_COMPATIBILITY]; 31699c821b0SMatthew Brost 317c73acc1eSFrancois Dugast xe_gt_assert(gt, uc_fw->type == XE_UC_FW_TYPE_GUC); 31899c821b0SMatthew Brost 3194eb0aab6SJulia Filipchuk /* We don't support GuC releases older than 70.29.2 */ 3204eb0aab6SJulia Filipchuk if (MAKE_GUC_VER_STRUCT(*release) < MAKE_GUC_VER(70, 29, 2)) { 3214eb0aab6SJulia Filipchuk xe_gt_err(gt, "Unsupported GuC v%u.%u.%u! v70.29.2 or newer is required\n", 3224eb0aab6SJulia Filipchuk release->major, release->minor, release->patch); 32343c4ff3cSDaniele Ceraolo Spurio return -EINVAL; 32499c821b0SMatthew Brost } 32599c821b0SMatthew Brost 32643c4ff3cSDaniele Ceraolo Spurio compatibility->major = FIELD_GET(CSS_SW_VERSION_UC_MAJOR, css->submission_version); 32743c4ff3cSDaniele Ceraolo Spurio compatibility->minor = FIELD_GET(CSS_SW_VERSION_UC_MINOR, css->submission_version); 32843c4ff3cSDaniele Ceraolo Spurio compatibility->patch = FIELD_GET(CSS_SW_VERSION_UC_PATCH, css->submission_version); 32943c4ff3cSDaniele Ceraolo Spurio 33099c821b0SMatthew Brost uc_fw->private_data_size = css->private_data_size; 33143c4ff3cSDaniele Ceraolo Spurio 33243c4ff3cSDaniele Ceraolo Spurio return 0; 33399c821b0SMatthew Brost } 33499c821b0SMatthew Brost 3350881cbe0SDaniele Ceraolo Spurio int xe_uc_fw_check_version_requirements(struct xe_uc_fw *uc_fw) 336ad55ead7SLucas De Marchi { 337ad55ead7SLucas De Marchi struct xe_device *xe = uc_fw_to_xe(uc_fw); 3382e7227b4SDaniele Ceraolo Spurio struct xe_uc_fw_version *wanted = &uc_fw->versions.wanted; 3392e7227b4SDaniele Ceraolo Spurio struct xe_uc_fw_version *found = &uc_fw->versions.found[uc_fw->versions.wanted_type]; 340ad55ead7SLucas De Marchi 341ad55ead7SLucas De Marchi /* Driver has no requirement on any version, any is good. */ 3422e7227b4SDaniele Ceraolo Spurio if (!wanted->major) 343ad55ead7SLucas De Marchi return 0; 344ad55ead7SLucas De Marchi 345ad55ead7SLucas De Marchi /* 346ad55ead7SLucas De Marchi * If full version is required, both major and minor should match. 347ad55ead7SLucas De Marchi * Otherwise, at least the major version. 348ad55ead7SLucas De Marchi */ 3492e7227b4SDaniele Ceraolo Spurio if (wanted->major != found->major || 3506650ad3eSJohn Harrison (uc_fw->full_ver_required && 3516650ad3eSJohn Harrison ((wanted->minor != found->minor) || 3526650ad3eSJohn Harrison (wanted->patch != found->patch)))) { 3536650ad3eSJohn Harrison drm_notice(&xe->drm, "%s firmware %s: unexpected version: %u.%u.%u != %u.%u.%u\n", 354ad55ead7SLucas De Marchi xe_uc_fw_type_repr(uc_fw->type), uc_fw->path, 3556650ad3eSJohn Harrison found->major, found->minor, found->patch, 3566650ad3eSJohn Harrison wanted->major, wanted->minor, wanted->patch); 357ad55ead7SLucas De Marchi goto fail; 358ad55ead7SLucas De Marchi } 359ad55ead7SLucas De Marchi 3606650ad3eSJohn Harrison if (wanted->minor > found->minor || 3616650ad3eSJohn Harrison (wanted->minor == found->minor && wanted->patch > found->patch)) { 3626650ad3eSJohn Harrison drm_notice(&xe->drm, "%s firmware (%u.%u.%u) is recommended, but only (%u.%u.%u) was found in %s\n", 363ad55ead7SLucas De Marchi xe_uc_fw_type_repr(uc_fw->type), 3646650ad3eSJohn Harrison wanted->major, wanted->minor, wanted->patch, 3656650ad3eSJohn Harrison found->major, found->minor, found->patch, 366ad55ead7SLucas De Marchi uc_fw->path); 367ad55ead7SLucas De Marchi drm_info(&xe->drm, "Consider updating your linux-firmware pkg or downloading from %s\n", 368ad55ead7SLucas De Marchi XE_UC_FIRMWARE_URL); 369ad55ead7SLucas De Marchi } 370ad55ead7SLucas De Marchi 371ad55ead7SLucas De Marchi return 0; 372ad55ead7SLucas De Marchi 373ad55ead7SLucas De Marchi fail: 374ad55ead7SLucas De Marchi if (xe_uc_fw_is_overridden(uc_fw)) 375ad55ead7SLucas De Marchi return 0; 376ad55ead7SLucas De Marchi 377ad55ead7SLucas De Marchi return -ENOEXEC; 378ad55ead7SLucas De Marchi } 379ad55ead7SLucas De Marchi 380a9a95523SDaniele Ceraolo Spurio /* Refer to the "CSS-based Firmware Layout" documentation entry for details */ 381a9a95523SDaniele Ceraolo Spurio static int parse_css_header(struct xe_uc_fw *uc_fw, const void *fw_data, size_t fw_size) 382a9a95523SDaniele Ceraolo Spurio { 383a9a95523SDaniele Ceraolo Spurio struct xe_device *xe = uc_fw_to_xe(uc_fw); 3842e7227b4SDaniele Ceraolo Spurio struct xe_uc_fw_version *release = &uc_fw->versions.found[XE_UC_FW_VER_RELEASE]; 385a9a95523SDaniele Ceraolo Spurio struct uc_css_header *css; 386a9a95523SDaniele Ceraolo Spurio size_t size; 387a9a95523SDaniele Ceraolo Spurio 388a9a95523SDaniele Ceraolo Spurio /* Check the size of the blob before examining buffer contents */ 389a9a95523SDaniele Ceraolo Spurio if (unlikely(fw_size < sizeof(struct uc_css_header))) { 390a9a95523SDaniele Ceraolo Spurio drm_warn(&xe->drm, "%s firmware %s: invalid size: %zu < %zu\n", 391a9a95523SDaniele Ceraolo Spurio xe_uc_fw_type_repr(uc_fw->type), uc_fw->path, 392a9a95523SDaniele Ceraolo Spurio fw_size, sizeof(struct uc_css_header)); 393a9a95523SDaniele Ceraolo Spurio return -ENODATA; 394a9a95523SDaniele Ceraolo Spurio } 395a9a95523SDaniele Ceraolo Spurio 396a9a95523SDaniele Ceraolo Spurio css = (struct uc_css_header *)fw_data; 397a9a95523SDaniele Ceraolo Spurio 398a9a95523SDaniele Ceraolo Spurio /* Check integrity of size values inside CSS header */ 399a9a95523SDaniele Ceraolo Spurio size = (css->header_size_dw - css->key_size_dw - css->modulus_size_dw - 400a9a95523SDaniele Ceraolo Spurio css->exponent_size_dw) * sizeof(u32); 401a9a95523SDaniele Ceraolo Spurio if (unlikely(size != sizeof(struct uc_css_header))) { 402a9a95523SDaniele Ceraolo Spurio drm_warn(&xe->drm, 403a9a95523SDaniele Ceraolo Spurio "%s firmware %s: unexpected header size: %zu != %zu\n", 404a9a95523SDaniele Ceraolo Spurio xe_uc_fw_type_repr(uc_fw->type), uc_fw->path, 405a9a95523SDaniele Ceraolo Spurio fw_size, sizeof(struct uc_css_header)); 406a9a95523SDaniele Ceraolo Spurio return -EPROTO; 407a9a95523SDaniele Ceraolo Spurio } 408a9a95523SDaniele Ceraolo Spurio 409a9a95523SDaniele Ceraolo Spurio /* uCode size must calculated from other sizes */ 410a9a95523SDaniele Ceraolo Spurio uc_fw->ucode_size = (css->size_dw - css->header_size_dw) * sizeof(u32); 411a9a95523SDaniele Ceraolo Spurio 412a9a95523SDaniele Ceraolo Spurio /* now RSA */ 413a9a95523SDaniele Ceraolo Spurio uc_fw->rsa_size = css->key_size_dw * sizeof(u32); 414a9a95523SDaniele Ceraolo Spurio 415a9a95523SDaniele Ceraolo Spurio /* At least, it should have header, uCode and RSA. Size of all three. */ 416a9a95523SDaniele Ceraolo Spurio size = sizeof(struct uc_css_header) + uc_fw->ucode_size + 417a9a95523SDaniele Ceraolo Spurio uc_fw->rsa_size; 418a9a95523SDaniele Ceraolo Spurio if (unlikely(fw_size < size)) { 419a9a95523SDaniele Ceraolo Spurio drm_warn(&xe->drm, "%s firmware %s: invalid size: %zu < %zu\n", 420a9a95523SDaniele Ceraolo Spurio xe_uc_fw_type_repr(uc_fw->type), uc_fw->path, 421a9a95523SDaniele Ceraolo Spurio fw_size, size); 422a9a95523SDaniele Ceraolo Spurio return -ENOEXEC; 423a9a95523SDaniele Ceraolo Spurio } 424a9a95523SDaniele Ceraolo Spurio 425a9a95523SDaniele Ceraolo Spurio /* Get version numbers from the CSS header */ 4262e7227b4SDaniele Ceraolo Spurio release->major = FIELD_GET(CSS_SW_VERSION_UC_MAJOR, css->sw_version); 4272e7227b4SDaniele Ceraolo Spurio release->minor = FIELD_GET(CSS_SW_VERSION_UC_MINOR, css->sw_version); 4282e7227b4SDaniele Ceraolo Spurio release->patch = FIELD_GET(CSS_SW_VERSION_UC_PATCH, css->sw_version); 429a9a95523SDaniele Ceraolo Spurio 430a9a95523SDaniele Ceraolo Spurio if (uc_fw->type == XE_UC_FW_TYPE_GUC) 43143c4ff3cSDaniele Ceraolo Spurio return guc_read_css_info(uc_fw, css); 432a9a95523SDaniele Ceraolo Spurio 433a9a95523SDaniele Ceraolo Spurio return 0; 434a9a95523SDaniele Ceraolo Spurio } 435a9a95523SDaniele Ceraolo Spurio 436484ecffaSDaniele Ceraolo Spurio static bool is_cpd_header(const void *data) 437484ecffaSDaniele Ceraolo Spurio { 438484ecffaSDaniele Ceraolo Spurio const u32 *marker = data; 439484ecffaSDaniele Ceraolo Spurio 440484ecffaSDaniele Ceraolo Spurio return *marker == GSC_CPD_HEADER_MARKER; 441484ecffaSDaniele Ceraolo Spurio } 442484ecffaSDaniele Ceraolo Spurio 443484ecffaSDaniele Ceraolo Spurio static u32 entry_offset(const struct gsc_cpd_header_v2 *header, const char *name) 444484ecffaSDaniele Ceraolo Spurio { 445484ecffaSDaniele Ceraolo Spurio const struct gsc_cpd_entry *entry; 446484ecffaSDaniele Ceraolo Spurio int i; 447484ecffaSDaniele Ceraolo Spurio 448484ecffaSDaniele Ceraolo Spurio entry = (void *)header + header->header_length; 449484ecffaSDaniele Ceraolo Spurio 450484ecffaSDaniele Ceraolo Spurio for (i = 0; i < header->num_of_entries; i++, entry++) 451484ecffaSDaniele Ceraolo Spurio if (strcmp(entry->name, name) == 0) 452484ecffaSDaniele Ceraolo Spurio return entry->offset & GSC_CPD_ENTRY_OFFSET_MASK; 453484ecffaSDaniele Ceraolo Spurio 454484ecffaSDaniele Ceraolo Spurio return 0; 455484ecffaSDaniele Ceraolo Spurio } 456484ecffaSDaniele Ceraolo Spurio 457484ecffaSDaniele Ceraolo Spurio /* Refer to the "GSC-based Firmware Layout" documentation entry for details */ 458484ecffaSDaniele Ceraolo Spurio static int parse_cpd_header(struct xe_uc_fw *uc_fw, const void *data, size_t size, 459484ecffaSDaniele Ceraolo Spurio const char *manifest_entry, const char *css_entry) 460484ecffaSDaniele Ceraolo Spurio { 461484ecffaSDaniele Ceraolo Spurio struct xe_gt *gt = uc_fw_to_gt(uc_fw); 462484ecffaSDaniele Ceraolo Spurio struct xe_device *xe = gt_to_xe(gt); 463484ecffaSDaniele Ceraolo Spurio const struct gsc_cpd_header_v2 *header = data; 4642e7227b4SDaniele Ceraolo Spurio struct xe_uc_fw_version *release = &uc_fw->versions.found[XE_UC_FW_VER_RELEASE]; 465484ecffaSDaniele Ceraolo Spurio const struct gsc_manifest_header *manifest; 466484ecffaSDaniele Ceraolo Spurio size_t min_size = sizeof(*header); 467484ecffaSDaniele Ceraolo Spurio u32 offset; 468484ecffaSDaniele Ceraolo Spurio 469484ecffaSDaniele Ceraolo Spurio /* manifest_entry is mandatory, css_entry is optional */ 470484ecffaSDaniele Ceraolo Spurio xe_assert(xe, manifest_entry); 471484ecffaSDaniele Ceraolo Spurio 472484ecffaSDaniele Ceraolo Spurio if (size < min_size || !is_cpd_header(header)) 473484ecffaSDaniele Ceraolo Spurio return -ENOENT; 474484ecffaSDaniele Ceraolo Spurio 475484ecffaSDaniele Ceraolo Spurio if (header->header_length < sizeof(struct gsc_cpd_header_v2)) { 476484ecffaSDaniele Ceraolo Spurio xe_gt_err(gt, "invalid CPD header length %u!\n", header->header_length); 477484ecffaSDaniele Ceraolo Spurio return -EINVAL; 478484ecffaSDaniele Ceraolo Spurio } 479484ecffaSDaniele Ceraolo Spurio 480484ecffaSDaniele Ceraolo Spurio min_size = header->header_length + sizeof(struct gsc_cpd_entry) * header->num_of_entries; 481484ecffaSDaniele Ceraolo Spurio if (size < min_size) { 482484ecffaSDaniele Ceraolo Spurio xe_gt_err(gt, "FW too small! %zu < %zu\n", size, min_size); 483484ecffaSDaniele Ceraolo Spurio return -ENODATA; 484484ecffaSDaniele Ceraolo Spurio } 485484ecffaSDaniele Ceraolo Spurio 486484ecffaSDaniele Ceraolo Spurio /* Look for the manifest first */ 487484ecffaSDaniele Ceraolo Spurio offset = entry_offset(header, manifest_entry); 488484ecffaSDaniele Ceraolo Spurio if (!offset) { 489484ecffaSDaniele Ceraolo Spurio xe_gt_err(gt, "Failed to find %s manifest!\n", 490484ecffaSDaniele Ceraolo Spurio xe_uc_fw_type_repr(uc_fw->type)); 491484ecffaSDaniele Ceraolo Spurio return -ENODATA; 492484ecffaSDaniele Ceraolo Spurio } 493484ecffaSDaniele Ceraolo Spurio 494484ecffaSDaniele Ceraolo Spurio min_size = offset + sizeof(struct gsc_manifest_header); 495484ecffaSDaniele Ceraolo Spurio if (size < min_size) { 496484ecffaSDaniele Ceraolo Spurio xe_gt_err(gt, "FW too small! %zu < %zu\n", size, min_size); 497484ecffaSDaniele Ceraolo Spurio return -ENODATA; 498484ecffaSDaniele Ceraolo Spurio } 499484ecffaSDaniele Ceraolo Spurio 500484ecffaSDaniele Ceraolo Spurio manifest = data + offset; 501484ecffaSDaniele Ceraolo Spurio 5022e7227b4SDaniele Ceraolo Spurio release->major = manifest->fw_version.major; 5032e7227b4SDaniele Ceraolo Spurio release->minor = manifest->fw_version.minor; 5042e7227b4SDaniele Ceraolo Spurio release->patch = manifest->fw_version.hotfix; 505484ecffaSDaniele Ceraolo Spurio 506985d5a49SDaniele Ceraolo Spurio if (uc_fw->type == XE_UC_FW_TYPE_GSC) { 507985d5a49SDaniele Ceraolo Spurio struct xe_gsc *gsc = container_of(uc_fw, struct xe_gsc, fw); 508985d5a49SDaniele Ceraolo Spurio 509985d5a49SDaniele Ceraolo Spurio release->build = manifest->fw_version.build; 510985d5a49SDaniele Ceraolo Spurio gsc->security_version = manifest->security_version; 511985d5a49SDaniele Ceraolo Spurio } 512985d5a49SDaniele Ceraolo Spurio 513484ecffaSDaniele Ceraolo Spurio /* then optionally look for the css header */ 514484ecffaSDaniele Ceraolo Spurio if (css_entry) { 515484ecffaSDaniele Ceraolo Spurio int ret; 516484ecffaSDaniele Ceraolo Spurio 517484ecffaSDaniele Ceraolo Spurio /* 518484ecffaSDaniele Ceraolo Spurio * This section does not contain a CSS entry on DG2. We 519484ecffaSDaniele Ceraolo Spurio * don't support DG2 HuC right now, so no need to handle 520484ecffaSDaniele Ceraolo Spurio * it, just add a reminder in case that changes. 521484ecffaSDaniele Ceraolo Spurio */ 522484ecffaSDaniele Ceraolo Spurio xe_assert(xe, xe->info.platform != XE_DG2); 523484ecffaSDaniele Ceraolo Spurio 524484ecffaSDaniele Ceraolo Spurio offset = entry_offset(header, css_entry); 525484ecffaSDaniele Ceraolo Spurio 526484ecffaSDaniele Ceraolo Spurio /* the CSS header parser will check that the CSS header fits */ 527484ecffaSDaniele Ceraolo Spurio if (offset > size) { 528484ecffaSDaniele Ceraolo Spurio xe_gt_err(gt, "FW too small! %zu < %u\n", size, offset); 529484ecffaSDaniele Ceraolo Spurio return -ENODATA; 530484ecffaSDaniele Ceraolo Spurio } 531484ecffaSDaniele Ceraolo Spurio 532484ecffaSDaniele Ceraolo Spurio ret = parse_css_header(uc_fw, data + offset, size - offset); 533484ecffaSDaniele Ceraolo Spurio if (ret) 534484ecffaSDaniele Ceraolo Spurio return ret; 535484ecffaSDaniele Ceraolo Spurio 536484ecffaSDaniele Ceraolo Spurio uc_fw->css_offset = offset; 537484ecffaSDaniele Ceraolo Spurio } 538484ecffaSDaniele Ceraolo Spurio 539d8b15713SDaniele Ceraolo Spurio uc_fw->has_gsc_headers = true; 540d8b15713SDaniele Ceraolo Spurio 541484ecffaSDaniele Ceraolo Spurio return 0; 542484ecffaSDaniele Ceraolo Spurio } 543484ecffaSDaniele Ceraolo Spurio 544985d5a49SDaniele Ceraolo Spurio static int parse_gsc_layout(struct xe_uc_fw *uc_fw, const void *data, size_t size) 545985d5a49SDaniele Ceraolo Spurio { 546985d5a49SDaniele Ceraolo Spurio struct xe_gt *gt = uc_fw_to_gt(uc_fw); 547985d5a49SDaniele Ceraolo Spurio const struct gsc_layout_pointers *layout = data; 548985d5a49SDaniele Ceraolo Spurio const struct gsc_bpdt_header *bpdt_header = NULL; 549985d5a49SDaniele Ceraolo Spurio const struct gsc_bpdt_entry *bpdt_entry = NULL; 550985d5a49SDaniele Ceraolo Spurio size_t min_size = sizeof(*layout); 551985d5a49SDaniele Ceraolo Spurio int i; 552985d5a49SDaniele Ceraolo Spurio 553985d5a49SDaniele Ceraolo Spurio if (size < min_size) { 554985d5a49SDaniele Ceraolo Spurio xe_gt_err(gt, "GSC FW too small! %zu < %zu\n", size, min_size); 555985d5a49SDaniele Ceraolo Spurio return -ENODATA; 556985d5a49SDaniele Ceraolo Spurio } 557985d5a49SDaniele Ceraolo Spurio 558985d5a49SDaniele Ceraolo Spurio min_size = layout->boot1.offset + layout->boot1.size; 559985d5a49SDaniele Ceraolo Spurio if (size < min_size) { 560985d5a49SDaniele Ceraolo Spurio xe_gt_err(gt, "GSC FW too small for boot section! %zu < %zu\n", 561985d5a49SDaniele Ceraolo Spurio size, min_size); 562985d5a49SDaniele Ceraolo Spurio return -ENODATA; 563985d5a49SDaniele Ceraolo Spurio } 564985d5a49SDaniele Ceraolo Spurio 565985d5a49SDaniele Ceraolo Spurio min_size = sizeof(*bpdt_header); 566985d5a49SDaniele Ceraolo Spurio if (layout->boot1.size < min_size) { 567985d5a49SDaniele Ceraolo Spurio xe_gt_err(gt, "GSC FW boot section too small for BPDT header: %u < %zu\n", 568985d5a49SDaniele Ceraolo Spurio layout->boot1.size, min_size); 569985d5a49SDaniele Ceraolo Spurio return -ENODATA; 570985d5a49SDaniele Ceraolo Spurio } 571985d5a49SDaniele Ceraolo Spurio 572985d5a49SDaniele Ceraolo Spurio bpdt_header = data + layout->boot1.offset; 573985d5a49SDaniele Ceraolo Spurio if (bpdt_header->signature != GSC_BPDT_HEADER_SIGNATURE) { 574985d5a49SDaniele Ceraolo Spurio xe_gt_err(gt, "invalid signature for BPDT header: 0x%08x!\n", 575985d5a49SDaniele Ceraolo Spurio bpdt_header->signature); 576985d5a49SDaniele Ceraolo Spurio return -EINVAL; 577985d5a49SDaniele Ceraolo Spurio } 578985d5a49SDaniele Ceraolo Spurio 579985d5a49SDaniele Ceraolo Spurio min_size += sizeof(*bpdt_entry) * bpdt_header->descriptor_count; 580985d5a49SDaniele Ceraolo Spurio if (layout->boot1.size < min_size) { 581985d5a49SDaniele Ceraolo Spurio xe_gt_err(gt, "GSC FW boot section too small for BPDT entries: %u < %zu\n", 582985d5a49SDaniele Ceraolo Spurio layout->boot1.size, min_size); 583985d5a49SDaniele Ceraolo Spurio return -ENODATA; 584985d5a49SDaniele Ceraolo Spurio } 585985d5a49SDaniele Ceraolo Spurio 586985d5a49SDaniele Ceraolo Spurio bpdt_entry = (void *)bpdt_header + sizeof(*bpdt_header); 587985d5a49SDaniele Ceraolo Spurio for (i = 0; i < bpdt_header->descriptor_count; i++, bpdt_entry++) { 588985d5a49SDaniele Ceraolo Spurio if ((bpdt_entry->type & GSC_BPDT_ENTRY_TYPE_MASK) != 589985d5a49SDaniele Ceraolo Spurio GSC_BPDT_ENTRY_TYPE_GSC_RBE) 590985d5a49SDaniele Ceraolo Spurio continue; 591985d5a49SDaniele Ceraolo Spurio 592985d5a49SDaniele Ceraolo Spurio min_size = bpdt_entry->sub_partition_offset; 593985d5a49SDaniele Ceraolo Spurio 594985d5a49SDaniele Ceraolo Spurio /* the CPD header parser will check that the CPD header fits */ 595985d5a49SDaniele Ceraolo Spurio if (layout->boot1.size < min_size) { 596985d5a49SDaniele Ceraolo Spurio xe_gt_err(gt, "GSC FW boot section too small for CPD offset: %u < %zu\n", 597985d5a49SDaniele Ceraolo Spurio layout->boot1.size, min_size); 598985d5a49SDaniele Ceraolo Spurio return -ENODATA; 599985d5a49SDaniele Ceraolo Spurio } 600985d5a49SDaniele Ceraolo Spurio 601985d5a49SDaniele Ceraolo Spurio return parse_cpd_header(uc_fw, 602985d5a49SDaniele Ceraolo Spurio (void *)bpdt_header + min_size, 603985d5a49SDaniele Ceraolo Spurio layout->boot1.size - min_size, 604985d5a49SDaniele Ceraolo Spurio "RBEP.man", NULL); 605985d5a49SDaniele Ceraolo Spurio } 606985d5a49SDaniele Ceraolo Spurio 607985d5a49SDaniele Ceraolo Spurio xe_gt_err(gt, "couldn't find CPD header in GSC binary!\n"); 608985d5a49SDaniele Ceraolo Spurio return -ENODATA; 609985d5a49SDaniele Ceraolo Spurio } 610985d5a49SDaniele Ceraolo Spurio 611a9a95523SDaniele Ceraolo Spurio static int parse_headers(struct xe_uc_fw *uc_fw, const struct firmware *fw) 612a9a95523SDaniele Ceraolo Spurio { 613484ecffaSDaniele Ceraolo Spurio int ret; 614484ecffaSDaniele Ceraolo Spurio 615484ecffaSDaniele Ceraolo Spurio /* 616484ecffaSDaniele Ceraolo Spurio * All GuC releases and older HuC ones use CSS headers, while newer HuC 617484ecffaSDaniele Ceraolo Spurio * releases use GSC CPD headers. 618484ecffaSDaniele Ceraolo Spurio */ 619484ecffaSDaniele Ceraolo Spurio switch (uc_fw->type) { 620985d5a49SDaniele Ceraolo Spurio case XE_UC_FW_TYPE_GSC: 621985d5a49SDaniele Ceraolo Spurio return parse_gsc_layout(uc_fw, fw->data, fw->size); 622484ecffaSDaniele Ceraolo Spurio case XE_UC_FW_TYPE_HUC: 623484ecffaSDaniele Ceraolo Spurio ret = parse_cpd_header(uc_fw, fw->data, fw->size, "HUCP.man", "huc_fw"); 624484ecffaSDaniele Ceraolo Spurio if (!ret || ret != -ENOENT) 625484ecffaSDaniele Ceraolo Spurio return ret; 626484ecffaSDaniele Ceraolo Spurio fallthrough; 627484ecffaSDaniele Ceraolo Spurio case XE_UC_FW_TYPE_GUC: 628a9a95523SDaniele Ceraolo Spurio return parse_css_header(uc_fw, fw->data, fw->size); 629484ecffaSDaniele Ceraolo Spurio default: 630484ecffaSDaniele Ceraolo Spurio return -EINVAL; 631484ecffaSDaniele Ceraolo Spurio } 632484ecffaSDaniele Ceraolo Spurio 633484ecffaSDaniele Ceraolo Spurio return 0; 634a9a95523SDaniele Ceraolo Spurio } 635a9a95523SDaniele Ceraolo Spurio 6362e7227b4SDaniele Ceraolo Spurio #define print_uc_fw_version(p_, version_, prefix_, ...) \ 6372e7227b4SDaniele Ceraolo Spurio do { \ 6382e7227b4SDaniele Ceraolo Spurio struct xe_uc_fw_version *ver_ = (version_); \ 6392e7227b4SDaniele Ceraolo Spurio if (ver_->build) \ 6402e7227b4SDaniele Ceraolo Spurio drm_printf(p_, prefix_ " version %u.%u.%u.%u\n", ##__VA_ARGS__, \ 6412e7227b4SDaniele Ceraolo Spurio ver_->major, ver_->minor, \ 6422e7227b4SDaniele Ceraolo Spurio ver_->patch, ver_->build); \ 6432e7227b4SDaniele Ceraolo Spurio else \ 6442e7227b4SDaniele Ceraolo Spurio drm_printf(p_, prefix_ " version %u.%u.%u\n", ##__VA_ARGS__, \ 6452e7227b4SDaniele Ceraolo Spurio ver_->major, ver_->minor, ver_->patch); \ 6462e7227b4SDaniele Ceraolo Spurio } while (0) 6472e7227b4SDaniele Ceraolo Spurio 648c93ea051SMichał Winiarski static int uc_fw_request(struct xe_uc_fw *uc_fw, const struct firmware **firmware_p) 649dd08ebf6SMatthew Brost { 650dd08ebf6SMatthew Brost struct xe_device *xe = uc_fw_to_xe(uc_fw); 651dd08ebf6SMatthew Brost struct device *dev = xe->drm.dev; 6522e7227b4SDaniele Ceraolo Spurio struct drm_printer p = drm_info_printer(dev); 653dd08ebf6SMatthew Brost const struct firmware *fw = NULL; 654dd08ebf6SMatthew Brost int err; 655dd08ebf6SMatthew Brost 656dd08ebf6SMatthew Brost /* 657dd08ebf6SMatthew Brost * we use FIRMWARE_UNINITIALIZED to detect checks against uc_fw->status 658dd08ebf6SMatthew Brost * before we're looked at the HW caps to see if we have uc support 659dd08ebf6SMatthew Brost */ 660dd08ebf6SMatthew Brost BUILD_BUG_ON(XE_UC_FIRMWARE_UNINITIALIZED); 661c73acc1eSFrancois Dugast xe_assert(xe, !uc_fw->status); 662c73acc1eSFrancois Dugast xe_assert(xe, !uc_fw->path); 663dd08ebf6SMatthew Brost 664dd08ebf6SMatthew Brost uc_fw_auto_select(xe, uc_fw); 66566cb3ca9SMichal Wajdeczko 66666cb3ca9SMichal Wajdeczko if (IS_SRIOV_VF(xe)) { 66705e49e0cSMichal Wajdeczko /* Only GuC/HuC are supported */ 66805e49e0cSMichal Wajdeczko if (uc_fw->type != XE_UC_FW_TYPE_GUC && 66905e49e0cSMichal Wajdeczko uc_fw->type != XE_UC_FW_TYPE_HUC) 67005e49e0cSMichal Wajdeczko uc_fw->path = NULL; 67166cb3ca9SMichal Wajdeczko /* VF will support only firmwares that driver can autoselect */ 67266cb3ca9SMichal Wajdeczko xe_uc_fw_change_status(uc_fw, uc_fw->path ? 67366cb3ca9SMichal Wajdeczko XE_UC_FIRMWARE_PRELOADED : 67466cb3ca9SMichal Wajdeczko XE_UC_FIRMWARE_NOT_SUPPORTED); 67566cb3ca9SMichal Wajdeczko return 0; 67666cb3ca9SMichal Wajdeczko } 67766cb3ca9SMichal Wajdeczko 67845883418SLucas De Marchi uc_fw_override(uc_fw); 67966cb3ca9SMichal Wajdeczko 68075730847SDaniele Ceraolo Spurio xe_uc_fw_change_status(uc_fw, uc_fw->path ? 681dd08ebf6SMatthew Brost XE_UC_FIRMWARE_SELECTED : 682dd08ebf6SMatthew Brost XE_UC_FIRMWARE_NOT_SUPPORTED); 683dd08ebf6SMatthew Brost 6846badfc46SLucas De Marchi if (!xe_uc_fw_is_supported(uc_fw)) { 6856badfc46SLucas De Marchi if (uc_fw->type == XE_UC_FW_TYPE_GUC) { 6866badfc46SLucas De Marchi drm_err(&xe->drm, "No GuC firmware defined for platform\n"); 6876badfc46SLucas De Marchi return -ENOENT; 6886badfc46SLucas De Marchi } 68975730847SDaniele Ceraolo Spurio return 0; 6906badfc46SLucas De Marchi } 69175730847SDaniele Ceraolo Spurio 692a455ed04SDaniele Ceraolo Spurio /* an empty path means the firmware is disabled */ 693a455ed04SDaniele Ceraolo Spurio if (!xe_device_uc_enabled(xe) || !(*uc_fw->path)) { 694dd08ebf6SMatthew Brost xe_uc_fw_change_status(uc_fw, XE_UC_FIRMWARE_DISABLED); 69575730847SDaniele Ceraolo Spurio drm_dbg(&xe->drm, "%s disabled", xe_uc_fw_type_repr(uc_fw->type)); 69675730847SDaniele Ceraolo Spurio return 0; 697dd08ebf6SMatthew Brost } 69875730847SDaniele Ceraolo Spurio 699dd08ebf6SMatthew Brost err = request_firmware(&fw, uc_fw->path, dev); 700dd08ebf6SMatthew Brost if (err) 701dd08ebf6SMatthew Brost goto fail; 702dd08ebf6SMatthew Brost 703a9a95523SDaniele Ceraolo Spurio err = parse_headers(uc_fw, fw); 704a9a95523SDaniele Ceraolo Spurio if (err) 705dd08ebf6SMatthew Brost goto fail; 706dd08ebf6SMatthew Brost 7072e7227b4SDaniele Ceraolo Spurio print_uc_fw_version(&p, 7082e7227b4SDaniele Ceraolo Spurio &uc_fw->versions.found[XE_UC_FW_VER_RELEASE], 7092e7227b4SDaniele Ceraolo Spurio "Using %s firmware from %s", 7102e7227b4SDaniele Ceraolo Spurio xe_uc_fw_type_repr(uc_fw->type), uc_fw->path); 71161e72e77SLucas De Marchi 7120881cbe0SDaniele Ceraolo Spurio /* for GSC FW we want the compatibility version, which we query after load */ 7130881cbe0SDaniele Ceraolo Spurio if (uc_fw->type != XE_UC_FW_TYPE_GSC) { 7140881cbe0SDaniele Ceraolo Spurio err = xe_uc_fw_check_version_requirements(uc_fw); 715ad55ead7SLucas De Marchi if (err) 716dd08ebf6SMatthew Brost goto fail; 7170881cbe0SDaniele Ceraolo Spurio } 718dd08ebf6SMatthew Brost 719c93ea051SMichał Winiarski *firmware_p = fw; 720dd08ebf6SMatthew Brost 721dd08ebf6SMatthew Brost return 0; 722dd08ebf6SMatthew Brost 723dd08ebf6SMatthew Brost fail: 724dd08ebf6SMatthew Brost xe_uc_fw_change_status(uc_fw, err == -ENOENT ? 725dd08ebf6SMatthew Brost XE_UC_FIRMWARE_MISSING : 726dd08ebf6SMatthew Brost XE_UC_FIRMWARE_ERROR); 727dd08ebf6SMatthew Brost 728dd08ebf6SMatthew Brost drm_notice(&xe->drm, "%s firmware %s: fetch failed with error %d\n", 729dd08ebf6SMatthew Brost xe_uc_fw_type_repr(uc_fw->type), uc_fw->path, err); 730dd08ebf6SMatthew Brost drm_info(&xe->drm, "%s firmware(s) can be downloaded from %s\n", 731dd08ebf6SMatthew Brost xe_uc_fw_type_repr(uc_fw->type), XE_UC_FIRMWARE_URL); 732dd08ebf6SMatthew Brost 733dd08ebf6SMatthew Brost release_firmware(fw); /* OK even if fw is NULL */ 7340e1a47fcSMichał Winiarski 735dd08ebf6SMatthew Brost return err; 736dd08ebf6SMatthew Brost } 737dd08ebf6SMatthew Brost 738c93ea051SMichał Winiarski static void uc_fw_release(const struct firmware *fw) 739c93ea051SMichał Winiarski { 740c93ea051SMichał Winiarski release_firmware(fw); 741c93ea051SMichał Winiarski } 742c93ea051SMichał Winiarski 743c93ea051SMichał Winiarski static int uc_fw_copy(struct xe_uc_fw *uc_fw, const void *data, size_t size, u32 flags) 744c93ea051SMichał Winiarski { 745c93ea051SMichał Winiarski struct xe_device *xe = uc_fw_to_xe(uc_fw); 746c93ea051SMichał Winiarski struct xe_gt *gt = uc_fw_to_gt(uc_fw); 747c93ea051SMichał Winiarski struct xe_tile *tile = gt_to_tile(gt); 748c93ea051SMichał Winiarski struct xe_bo *obj; 749c93ea051SMichał Winiarski int err; 750c93ea051SMichał Winiarski 751c93ea051SMichał Winiarski obj = xe_managed_bo_create_from_data(xe, tile, data, size, flags); 752c93ea051SMichał Winiarski if (IS_ERR(obj)) { 753c93ea051SMichał Winiarski drm_notice(&xe->drm, "%s firmware %s: failed to create / populate bo", 754c93ea051SMichał Winiarski xe_uc_fw_type_repr(uc_fw->type), uc_fw->path); 755c93ea051SMichał Winiarski err = PTR_ERR(obj); 756c93ea051SMichał Winiarski goto fail; 757c93ea051SMichał Winiarski } 758c93ea051SMichał Winiarski 759c93ea051SMichał Winiarski uc_fw->bo = obj; 760c93ea051SMichał Winiarski uc_fw->size = size; 761c93ea051SMichał Winiarski 762c93ea051SMichał Winiarski xe_uc_fw_change_status(uc_fw, XE_UC_FIRMWARE_AVAILABLE); 763c93ea051SMichał Winiarski 764c93ea051SMichał Winiarski err = drmm_add_action_or_reset(&xe->drm, uc_fw_fini, uc_fw); 765c93ea051SMichał Winiarski if (err) 766c93ea051SMichał Winiarski goto fail; 767c93ea051SMichał Winiarski 768c93ea051SMichał Winiarski return 0; 769c93ea051SMichał Winiarski 770c93ea051SMichał Winiarski fail: 771c93ea051SMichał Winiarski xe_uc_fw_change_status(uc_fw, XE_UC_FIRMWARE_ERROR); 772c93ea051SMichał Winiarski drm_notice(&xe->drm, "%s firmware %s: copy failed with error %d\n", 773c93ea051SMichał Winiarski xe_uc_fw_type_repr(uc_fw->type), uc_fw->path, err); 774c93ea051SMichał Winiarski 775c93ea051SMichał Winiarski return err; 776c93ea051SMichał Winiarski } 777c93ea051SMichał Winiarski 778c93ea051SMichał Winiarski int xe_uc_fw_init(struct xe_uc_fw *uc_fw) 779c93ea051SMichał Winiarski { 780c93ea051SMichał Winiarski const struct firmware *fw = NULL; 781c93ea051SMichał Winiarski int err; 782c93ea051SMichał Winiarski 783c93ea051SMichał Winiarski err = uc_fw_request(uc_fw, &fw); 784c93ea051SMichał Winiarski if (err) 785c93ea051SMichał Winiarski return err; 786c93ea051SMichał Winiarski 787c93ea051SMichał Winiarski /* no error and no firmware means nothing to copy */ 788c93ea051SMichał Winiarski if (!fw) 789c93ea051SMichał Winiarski return 0; 790c93ea051SMichał Winiarski 791c93ea051SMichał Winiarski err = uc_fw_copy(uc_fw, fw->data, fw->size, 79262742d12SLucas De Marchi XE_BO_FLAG_SYSTEM | XE_BO_FLAG_GGTT | 79362742d12SLucas De Marchi XE_BO_FLAG_GGTT_INVALIDATE); 794c93ea051SMichał Winiarski 795c93ea051SMichał Winiarski uc_fw_release(fw); 796c93ea051SMichał Winiarski 797c93ea051SMichał Winiarski return err; 798c93ea051SMichał Winiarski } 799c93ea051SMichał Winiarski 800dd08ebf6SMatthew Brost static u32 uc_fw_ggtt_offset(struct xe_uc_fw *uc_fw) 801dd08ebf6SMatthew Brost { 802dd08ebf6SMatthew Brost return xe_bo_ggtt_addr(uc_fw->bo); 803dd08ebf6SMatthew Brost } 804dd08ebf6SMatthew Brost 805dd08ebf6SMatthew Brost static int uc_fw_xfer(struct xe_uc_fw *uc_fw, u32 offset, u32 dma_flags) 806dd08ebf6SMatthew Brost { 807dd08ebf6SMatthew Brost struct xe_device *xe = uc_fw_to_xe(uc_fw); 808dd08ebf6SMatthew Brost struct xe_gt *gt = uc_fw_to_gt(uc_fw); 8094c15a6dcSDaniele Ceraolo Spurio u64 src_offset; 8104c15a6dcSDaniele Ceraolo Spurio u32 dma_ctrl; 811dd08ebf6SMatthew Brost int ret; 812dd08ebf6SMatthew Brost 813dd08ebf6SMatthew Brost xe_force_wake_assert_held(gt_to_fw(gt), XE_FW_GT); 814dd08ebf6SMatthew Brost 815dd08ebf6SMatthew Brost /* Set the source address for the uCode */ 816484ecffaSDaniele Ceraolo Spurio src_offset = uc_fw_ggtt_offset(uc_fw) + uc_fw->css_offset; 817ce8bf5bdSLucas De Marchi xe_mmio_write32(gt, DMA_ADDR_0_LOW, lower_32_bits(src_offset)); 818473b6276SFei Yang xe_mmio_write32(gt, DMA_ADDR_0_HIGH, 819473b6276SFei Yang upper_32_bits(src_offset) | DMA_ADDRESS_SPACE_GGTT); 820dd08ebf6SMatthew Brost 821dd08ebf6SMatthew Brost /* Set the DMA destination */ 822ce8bf5bdSLucas De Marchi xe_mmio_write32(gt, DMA_ADDR_1_LOW, offset); 823ce8bf5bdSLucas De Marchi xe_mmio_write32(gt, DMA_ADDR_1_HIGH, DMA_ADDRESS_SPACE_WOPCM); 824dd08ebf6SMatthew Brost 825dd08ebf6SMatthew Brost /* 826dd08ebf6SMatthew Brost * Set the transfer size. The header plus uCode will be copied to WOPCM 827dd08ebf6SMatthew Brost * via DMA, excluding any other components 828dd08ebf6SMatthew Brost */ 829ce8bf5bdSLucas De Marchi xe_mmio_write32(gt, DMA_COPY_SIZE, 830dd08ebf6SMatthew Brost sizeof(struct uc_css_header) + uc_fw->ucode_size); 831dd08ebf6SMatthew Brost 832dd08ebf6SMatthew Brost /* Start the DMA */ 833ce8bf5bdSLucas De Marchi xe_mmio_write32(gt, DMA_CTRL, 834dd08ebf6SMatthew Brost _MASKED_BIT_ENABLE(dma_flags | START_DMA)); 835dd08ebf6SMatthew Brost 836dd08ebf6SMatthew Brost /* Wait for DMA to finish */ 837063e09afSRodrigo Vivi ret = xe_mmio_wait32(gt, DMA_CTRL, START_DMA, 0, 100000, &dma_ctrl, 8387dc9b92dSRodrigo Vivi false); 839dd08ebf6SMatthew Brost if (ret) 840dd08ebf6SMatthew Brost drm_err(&xe->drm, "DMA for %s fw failed, DMA_CTRL=%u\n", 8417aaec3a6SRodrigo Vivi xe_uc_fw_type_repr(uc_fw->type), dma_ctrl); 842dd08ebf6SMatthew Brost 843dd08ebf6SMatthew Brost /* Disable the bits once DMA is over */ 844ce8bf5bdSLucas De Marchi xe_mmio_write32(gt, DMA_CTRL, _MASKED_BIT_DISABLE(dma_flags)); 845dd08ebf6SMatthew Brost 846dd08ebf6SMatthew Brost return ret; 847dd08ebf6SMatthew Brost } 848dd08ebf6SMatthew Brost 849dd08ebf6SMatthew Brost int xe_uc_fw_upload(struct xe_uc_fw *uc_fw, u32 offset, u32 dma_flags) 850dd08ebf6SMatthew Brost { 851dd08ebf6SMatthew Brost struct xe_device *xe = uc_fw_to_xe(uc_fw); 852dd08ebf6SMatthew Brost int err; 853dd08ebf6SMatthew Brost 854dd08ebf6SMatthew Brost /* make sure the status was cleared the last time we reset the uc */ 855c73acc1eSFrancois Dugast xe_assert(xe, !xe_uc_fw_is_loaded(uc_fw)); 856dd08ebf6SMatthew Brost 857dd08ebf6SMatthew Brost if (!xe_uc_fw_is_loadable(uc_fw)) 858dd08ebf6SMatthew Brost return -ENOEXEC; 859dd08ebf6SMatthew Brost 860dd08ebf6SMatthew Brost /* Call custom loader */ 861dd08ebf6SMatthew Brost err = uc_fw_xfer(uc_fw, offset, dma_flags); 862dd08ebf6SMatthew Brost if (err) 863dd08ebf6SMatthew Brost goto fail; 864dd08ebf6SMatthew Brost 865dd08ebf6SMatthew Brost xe_uc_fw_change_status(uc_fw, XE_UC_FIRMWARE_TRANSFERRED); 866dd08ebf6SMatthew Brost return 0; 867dd08ebf6SMatthew Brost 868dd08ebf6SMatthew Brost fail: 869dd08ebf6SMatthew Brost drm_err(&xe->drm, "Failed to load %s firmware %s (%d)\n", 870dd08ebf6SMatthew Brost xe_uc_fw_type_repr(uc_fw->type), uc_fw->path, 871dd08ebf6SMatthew Brost err); 872dd08ebf6SMatthew Brost xe_uc_fw_change_status(uc_fw, XE_UC_FIRMWARE_LOAD_FAIL); 873dd08ebf6SMatthew Brost return err; 874dd08ebf6SMatthew Brost } 875dd08ebf6SMatthew Brost 8762e7227b4SDaniele Ceraolo Spurio static const char *version_type_repr(enum xe_uc_fw_version_types type) 8772e7227b4SDaniele Ceraolo Spurio { 8782e7227b4SDaniele Ceraolo Spurio switch (type) { 8792e7227b4SDaniele Ceraolo Spurio case XE_UC_FW_VER_RELEASE: 8802e7227b4SDaniele Ceraolo Spurio return "release"; 8812e7227b4SDaniele Ceraolo Spurio case XE_UC_FW_VER_COMPATIBILITY: 8822e7227b4SDaniele Ceraolo Spurio return "compatibility"; 8832e7227b4SDaniele Ceraolo Spurio default: 8842e7227b4SDaniele Ceraolo Spurio return "Unknown version type"; 8852e7227b4SDaniele Ceraolo Spurio } 8862e7227b4SDaniele Ceraolo Spurio } 887dd08ebf6SMatthew Brost 888dd08ebf6SMatthew Brost void xe_uc_fw_print(struct xe_uc_fw *uc_fw, struct drm_printer *p) 889dd08ebf6SMatthew Brost { 8902e7227b4SDaniele Ceraolo Spurio int i; 8912e7227b4SDaniele Ceraolo Spurio 892dd08ebf6SMatthew Brost drm_printf(p, "%s firmware: %s\n", 893dd08ebf6SMatthew Brost xe_uc_fw_type_repr(uc_fw->type), uc_fw->path); 894dd08ebf6SMatthew Brost drm_printf(p, "\tstatus: %s\n", 895dd08ebf6SMatthew Brost xe_uc_fw_status_repr(uc_fw->status)); 89699c821b0SMatthew Brost 8972e7227b4SDaniele Ceraolo Spurio print_uc_fw_version(p, &uc_fw->versions.wanted, "\twanted %s", 8982e7227b4SDaniele Ceraolo Spurio version_type_repr(uc_fw->versions.wanted_type)); 89999c821b0SMatthew Brost 9002e7227b4SDaniele Ceraolo Spurio for (i = 0; i < XE_UC_FW_VER_TYPE_COUNT; i++) { 9012e7227b4SDaniele Ceraolo Spurio struct xe_uc_fw_version *ver = &uc_fw->versions.found[i]; 9022e7227b4SDaniele Ceraolo Spurio 9032e7227b4SDaniele Ceraolo Spurio if (ver->major) 9042e7227b4SDaniele Ceraolo Spurio print_uc_fw_version(p, ver, "\tfound %s", 9052e7227b4SDaniele Ceraolo Spurio version_type_repr(i)); 90699c821b0SMatthew Brost } 9072e7227b4SDaniele Ceraolo Spurio 9082e7227b4SDaniele Ceraolo Spurio if (uc_fw->ucode_size) 9092e7227b4SDaniele Ceraolo Spurio drm_printf(p, "\tuCode: %u bytes\n", uc_fw->ucode_size); 9102e7227b4SDaniele Ceraolo Spurio if (uc_fw->rsa_size) 9112e7227b4SDaniele Ceraolo Spurio drm_printf(p, "\tRSA: %u bytes\n", uc_fw->rsa_size); 912dd08ebf6SMatthew Brost } 913