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 11dd08ebf6SMatthew Brost #include "xe_bo.h" 12dd08ebf6SMatthew Brost #include "xe_device_types.h" 13dd08ebf6SMatthew Brost #include "xe_force_wake.h" 14dd08ebf6SMatthew Brost #include "xe_gt.h" 15dd08ebf6SMatthew Brost #include "xe_guc_reg.h" 16dd08ebf6SMatthew Brost #include "xe_map.h" 17dd08ebf6SMatthew Brost #include "xe_mmio.h" 18dd08ebf6SMatthew Brost #include "xe_uc_fw.h" 19dd08ebf6SMatthew Brost 20ad55ead7SLucas De Marchi /* 21ad55ead7SLucas De Marchi * List of required GuC and HuC binaries per-platform. They must be ordered 22ad55ead7SLucas De Marchi * based on platform, from newer to older. 23ad55ead7SLucas De Marchi * 24ad55ead7SLucas De Marchi * Versioning follows the guidelines from 25ad55ead7SLucas De Marchi * Documentation/driver-api/firmware/firmware-usage-guidelines.rst. There is a 26ad55ead7SLucas De Marchi * distinction for platforms being officially supported by the driver or not. 27ad55ead7SLucas De Marchi * Platforms not available publicly or not yet officially supported by the 28ad55ead7SLucas De Marchi * driver (under force-probe), use the mmp_ver(): the firmware autoselect logic 29ad55ead7SLucas De Marchi * will select the firmware from disk with filename that matches the full 30ad55ead7SLucas De Marchi * "mpp version", i.e. major.minor.patch. mmp_ver() should only be used for 31ad55ead7SLucas De Marchi * this case. 32ad55ead7SLucas De Marchi * 33ad55ead7SLucas De Marchi * For platforms officially supported by the driver, the filename always only 34ad55ead7SLucas De Marchi * ever contains the major version (GuC) or no version at all (HuC). 35ad55ead7SLucas De Marchi * 36ad55ead7SLucas De Marchi * After loading the file, the driver parses the versions embedded in the blob. 37ad55ead7SLucas De Marchi * The major version needs to match a major version supported by the driver (if 38ad55ead7SLucas De Marchi * any). The minor version is also checked and a notice emitted to the log if 39ad55ead7SLucas De Marchi * the version found is smaller than the version wanted. This is done only for 40ad55ead7SLucas De Marchi * informational purposes so users may have a chance to upgrade, but the driver 41ad55ead7SLucas De Marchi * still loads and use the older firmware. 42ad55ead7SLucas De Marchi * 43ad55ead7SLucas De Marchi * Examples: 44ad55ead7SLucas De Marchi * 45ad55ead7SLucas De Marchi * 1) Platform officially supported by i915 - using Tigerlake as example. 46ad55ead7SLucas De Marchi * Driver loads the following firmware blobs from disk: 47ad55ead7SLucas De Marchi * 48ad55ead7SLucas De Marchi * - i915/tgl_guc_<major>.bin 49ad55ead7SLucas De Marchi * - i915/tgl_huc.bin 50ad55ead7SLucas De Marchi * 51ad55ead7SLucas De Marchi * <major> number for GuC is checked that it matches the version inside 52ad55ead7SLucas De Marchi * the blob. <minor> version is checked and if smaller than the expected 53ad55ead7SLucas De Marchi * an info message is emitted about that. 54ad55ead7SLucas De Marchi * 55ad55ead7SLucas De Marchi * 1) XE_<FUTUREINTELPLATFORM>, still under require_force_probe. Using 56ad55ead7SLucas De Marchi * "wipplat" as a short-name. Driver loads the following firmware blobs 57ad55ead7SLucas De Marchi * from disk: 58ad55ead7SLucas De Marchi * 59ad55ead7SLucas De Marchi * - xe/wipplat_guc_<major>.<minor>.<patch>.bin 60ad55ead7SLucas De Marchi * - xe/wipplat_huc_<major>.<minor>.<patch>.bin 61ad55ead7SLucas De Marchi * 62ad55ead7SLucas De Marchi * <major> and <minor> are checked that they match the version inside 63ad55ead7SLucas De Marchi * the blob. Both of them need to match exactly what the driver is 64ad55ead7SLucas De Marchi * expecting, otherwise it fails. 65ad55ead7SLucas De Marchi * 66ad55ead7SLucas De Marchi * 3) Platform officially supported by xe and out of force-probe. Using 67ad55ead7SLucas De Marchi * "plat" as a short-name. Except for the different directory, the 68ad55ead7SLucas De Marchi * behavior is the same as (1). Driver loads the following firmware 69ad55ead7SLucas De Marchi * blobs from disk: 70ad55ead7SLucas De Marchi * 71ad55ead7SLucas De Marchi * - xe/plat_guc_<major>.bin 72ad55ead7SLucas De Marchi * - xe/plat_huc.bin 73ad55ead7SLucas De Marchi * 74ad55ead7SLucas De Marchi * <major> number for GuC is checked that it matches the version inside 75ad55ead7SLucas De Marchi * the blob. <minor> version is checked and if smaller than the expected 76ad55ead7SLucas De Marchi * an info message is emitted about that. 77ad55ead7SLucas De Marchi * 78ad55ead7SLucas De Marchi * For the platforms already released with a major version, they should never be 79ad55ead7SLucas De Marchi * removed from the table. Instead new entries with newer versions may be added 80ad55ead7SLucas De Marchi * before them, so they take precedence. 81ad55ead7SLucas De Marchi * 82ad55ead7SLucas De Marchi * TODO: Currently there's no fallback on major version. That's because xe 83ad55ead7SLucas De Marchi * driver only supports the one major version of each firmware in the table. 84ad55ead7SLucas De Marchi * This needs to be fixed when the major version of GuC is updated. 85ad55ead7SLucas De Marchi */ 86ad55ead7SLucas De Marchi 87ad55ead7SLucas De Marchi struct uc_fw_entry { 88ad55ead7SLucas De Marchi enum xe_platform platform; 89ad55ead7SLucas De Marchi struct { 90ad55ead7SLucas De Marchi const char *path; 91ad55ead7SLucas De Marchi u16 major; 92ad55ead7SLucas De Marchi u16 minor; 93ad55ead7SLucas De Marchi bool full_ver_required; 94ad55ead7SLucas De Marchi }; 95ad55ead7SLucas De Marchi }; 96ad55ead7SLucas De Marchi 97ad55ead7SLucas De Marchi struct fw_blobs_by_type { 98ad55ead7SLucas De Marchi const struct uc_fw_entry *entries; 99ad55ead7SLucas De Marchi u32 count; 100ad55ead7SLucas De Marchi }; 101ad55ead7SLucas De Marchi 102ad55ead7SLucas De Marchi #define XE_GUC_FIRMWARE_DEFS(fw_def, mmp_ver, major_ver) \ 103ad55ead7SLucas De Marchi fw_def(METEORLAKE, mmp_ver( i915, guc, mtl, 70, 6, 4)) \ 104ad55ead7SLucas De Marchi fw_def(PVC, mmp_ver( xe, guc, pvc, 70, 6, 4)) \ 105ad55ead7SLucas De Marchi fw_def(DG2, major_ver(i915, guc, dg2, 70, 5)) \ 106ad55ead7SLucas De Marchi fw_def(DG1, major_ver(i915, guc, dg1, 70, 5)) \ 107ad55ead7SLucas De Marchi fw_def(ALDERLAKE_P, major_ver(i915, guc, adlp, 70, 5)) \ 108ad55ead7SLucas De Marchi fw_def(ALDERLAKE_S, major_ver(i915, guc, tgl, 70, 5)) \ 109*94324e6bSAnusha Srivatsa fw_def(ROCKETLAKE, major_ver(i915, guc, tgl, 70, 5)) \ 110ad55ead7SLucas De Marchi fw_def(TIGERLAKE, major_ver(i915, guc, tgl, 70, 5)) 111ad55ead7SLucas De Marchi 112ad55ead7SLucas De Marchi #define XE_HUC_FIRMWARE_DEFS(fw_def, mmp_ver, no_ver) \ 113ad55ead7SLucas De Marchi fw_def(ALDERLAKE_S, no_ver(i915, huc, tgl)) \ 114ad55ead7SLucas De Marchi fw_def(DG1, no_ver(i915, huc, dg1)) \ 115*94324e6bSAnusha Srivatsa fw_def(ROCKETLAKE, no_ver(i915, huc, tgl)) \ 116ad55ead7SLucas De Marchi fw_def(TIGERLAKE, no_ver(i915, huc, tgl)) 117ad55ead7SLucas De Marchi 118ad55ead7SLucas De Marchi #define MAKE_FW_PATH(dir__, uc__, shortname__, version__) \ 119ad55ead7SLucas De Marchi __stringify(dir__) "/" __stringify(shortname__) "_" __stringify(uc__) version__ ".bin" 120ad55ead7SLucas De Marchi 121ad55ead7SLucas De Marchi #define fw_filename_mmp_ver(dir_, uc_, shortname_, a, b, c) \ 122ad55ead7SLucas De Marchi MAKE_FW_PATH(dir_, uc_, shortname_, "_" __stringify(a ## . ## b ## . ## c)) 123ad55ead7SLucas De Marchi #define fw_filename_major_ver(dir_, uc_, shortname_, a, b) \ 124ad55ead7SLucas De Marchi MAKE_FW_PATH(dir_, uc_, shortname_, "_" __stringify(a)) 125ad55ead7SLucas De Marchi #define fw_filename_no_ver(dir_, uc_, shortname_) \ 126ad55ead7SLucas De Marchi MAKE_FW_PATH(dir_, uc_, shortname_, "") 127ad55ead7SLucas De Marchi 128ad55ead7SLucas De Marchi #define uc_fw_entry_mmp_ver(dir_, uc_, shortname_, a, b, c) \ 129ad55ead7SLucas De Marchi { fw_filename_mmp_ver(dir_, uc_, shortname_, a, b, c), \ 130ad55ead7SLucas De Marchi a, b, true } 131ad55ead7SLucas De Marchi #define uc_fw_entry_major_ver(dir_, uc_, shortname_, a, b) \ 132ad55ead7SLucas De Marchi { fw_filename_major_ver(dir_, uc_, shortname_, a, b), \ 133ad55ead7SLucas De Marchi a, b } 134ad55ead7SLucas De Marchi #define uc_fw_entry_no_ver(dir_, uc_, shortname_) \ 135ad55ead7SLucas De Marchi { fw_filename_no_ver(dir_, uc_, shortname_), \ 136ad55ead7SLucas De Marchi 0, 0 } 137ad55ead7SLucas De Marchi 138ad55ead7SLucas De Marchi /* All blobs need to be declared via MODULE_FIRMWARE() */ 139ad55ead7SLucas De Marchi #define XE_UC_MODULE_FIRMWARE(platform__, fw_filename) \ 140ad55ead7SLucas De Marchi MODULE_FIRMWARE(fw_filename); 141ad55ead7SLucas De Marchi 142ad55ead7SLucas De Marchi #define XE_UC_FW_ENTRY(platform__, entry__) \ 143ad55ead7SLucas De Marchi { \ 144ad55ead7SLucas De Marchi .platform = XE_ ## platform__, \ 145ad55ead7SLucas De Marchi entry__, \ 146ad55ead7SLucas De Marchi }, 147ad55ead7SLucas De Marchi 148ad55ead7SLucas De Marchi XE_GUC_FIRMWARE_DEFS(XE_UC_MODULE_FIRMWARE, \ 149ad55ead7SLucas De Marchi fw_filename_mmp_ver, fw_filename_major_ver) 150ad55ead7SLucas De Marchi XE_HUC_FIRMWARE_DEFS(XE_UC_MODULE_FIRMWARE, \ 151ad55ead7SLucas De Marchi fw_filename_mmp_ver, fw_filename_no_ver) 152ad55ead7SLucas De Marchi 153dd08ebf6SMatthew Brost static struct xe_gt * 154dd08ebf6SMatthew Brost __uc_fw_to_gt(struct xe_uc_fw *uc_fw, enum xe_uc_fw_type type) 155dd08ebf6SMatthew Brost { 156dd08ebf6SMatthew Brost if (type == XE_UC_FW_TYPE_GUC) 157dd08ebf6SMatthew Brost return container_of(uc_fw, struct xe_gt, uc.guc.fw); 158dd08ebf6SMatthew Brost 159dd08ebf6SMatthew Brost XE_BUG_ON(type != XE_UC_FW_TYPE_HUC); 160dd08ebf6SMatthew Brost return container_of(uc_fw, struct xe_gt, uc.huc.fw); 161dd08ebf6SMatthew Brost } 162dd08ebf6SMatthew Brost 163dd08ebf6SMatthew Brost static struct xe_gt *uc_fw_to_gt(struct xe_uc_fw *uc_fw) 164dd08ebf6SMatthew Brost { 165dd08ebf6SMatthew Brost return __uc_fw_to_gt(uc_fw, uc_fw->type); 166dd08ebf6SMatthew Brost } 167dd08ebf6SMatthew Brost 168dd08ebf6SMatthew Brost static struct xe_device *uc_fw_to_xe(struct xe_uc_fw *uc_fw) 169dd08ebf6SMatthew Brost { 170dd08ebf6SMatthew Brost return gt_to_xe(uc_fw_to_gt(uc_fw)); 171dd08ebf6SMatthew Brost } 172dd08ebf6SMatthew Brost 173dd08ebf6SMatthew Brost static void 174dd08ebf6SMatthew Brost uc_fw_auto_select(struct xe_device *xe, struct xe_uc_fw *uc_fw) 175dd08ebf6SMatthew Brost { 176ad55ead7SLucas De Marchi static const struct uc_fw_entry entries_guc[] = { 177ad55ead7SLucas De Marchi XE_GUC_FIRMWARE_DEFS(XE_UC_FW_ENTRY, 178ad55ead7SLucas De Marchi uc_fw_entry_mmp_ver, 179ad55ead7SLucas De Marchi uc_fw_entry_major_ver) 180dd08ebf6SMatthew Brost }; 181ad55ead7SLucas De Marchi static const struct uc_fw_entry entries_huc[] = { 182ad55ead7SLucas De Marchi XE_HUC_FIRMWARE_DEFS(XE_UC_FW_ENTRY, 183ad55ead7SLucas De Marchi uc_fw_entry_mmp_ver, 184ad55ead7SLucas De Marchi uc_fw_entry_no_ver) 185dd08ebf6SMatthew Brost }; 186dd08ebf6SMatthew Brost static const struct fw_blobs_by_type blobs_all[XE_UC_FW_NUM_TYPES] = { 187ad55ead7SLucas De Marchi [XE_UC_FW_TYPE_GUC] = { entries_guc, ARRAY_SIZE(entries_guc) }, 188ad55ead7SLucas De Marchi [XE_UC_FW_TYPE_HUC] = { entries_huc, ARRAY_SIZE(entries_huc) }, 189dd08ebf6SMatthew Brost }; 190ad55ead7SLucas De Marchi static const struct uc_fw_entry *entries; 191dd08ebf6SMatthew Brost enum xe_platform p = xe->info.platform; 192ad55ead7SLucas De Marchi u32 count; 193dd08ebf6SMatthew Brost int i; 194dd08ebf6SMatthew Brost 195dd08ebf6SMatthew Brost XE_BUG_ON(uc_fw->type >= ARRAY_SIZE(blobs_all)); 196ad55ead7SLucas De Marchi entries = blobs_all[uc_fw->type].entries; 197ad55ead7SLucas De Marchi count = blobs_all[uc_fw->type].count; 198dd08ebf6SMatthew Brost 199ad55ead7SLucas De Marchi for (i = 0; i < count && p <= entries[i].platform; i++) { 200ad55ead7SLucas De Marchi if (p == entries[i].platform) { 201ad55ead7SLucas De Marchi uc_fw->path = entries[i].path; 202ad55ead7SLucas De Marchi uc_fw->major_ver_wanted = entries[i].major; 203ad55ead7SLucas De Marchi uc_fw->minor_ver_wanted = entries[i].minor; 204ad55ead7SLucas De Marchi uc_fw->full_ver_required = entries[i].full_ver_required; 205dd08ebf6SMatthew Brost break; 206dd08ebf6SMatthew Brost } 207dd08ebf6SMatthew Brost } 208dd08ebf6SMatthew Brost } 209dd08ebf6SMatthew Brost 210dd08ebf6SMatthew Brost /** 211dd08ebf6SMatthew Brost * xe_uc_fw_copy_rsa - copy fw RSA to buffer 212dd08ebf6SMatthew Brost * 213dd08ebf6SMatthew Brost * @uc_fw: uC firmware 214dd08ebf6SMatthew Brost * @dst: dst buffer 215dd08ebf6SMatthew Brost * @max_len: max number of bytes to copy 216dd08ebf6SMatthew Brost * 217dd08ebf6SMatthew Brost * Return: number of copied bytes. 218dd08ebf6SMatthew Brost */ 219dd08ebf6SMatthew Brost size_t xe_uc_fw_copy_rsa(struct xe_uc_fw *uc_fw, void *dst, u32 max_len) 220dd08ebf6SMatthew Brost { 221dd08ebf6SMatthew Brost struct xe_device *xe = uc_fw_to_xe(uc_fw); 222dd08ebf6SMatthew Brost u32 size = min_t(u32, uc_fw->rsa_size, max_len); 223dd08ebf6SMatthew Brost 224dd08ebf6SMatthew Brost XE_BUG_ON(size % 4); 225dd08ebf6SMatthew Brost XE_BUG_ON(!xe_uc_fw_is_available(uc_fw)); 226dd08ebf6SMatthew Brost 227dd08ebf6SMatthew Brost xe_map_memcpy_from(xe, dst, &uc_fw->bo->vmap, 228dd08ebf6SMatthew Brost xe_uc_fw_rsa_offset(uc_fw), size); 229dd08ebf6SMatthew Brost 230dd08ebf6SMatthew Brost return size; 231dd08ebf6SMatthew Brost } 232dd08ebf6SMatthew Brost 233dd08ebf6SMatthew Brost static void uc_fw_fini(struct drm_device *drm, void *arg) 234dd08ebf6SMatthew Brost { 235dd08ebf6SMatthew Brost struct xe_uc_fw *uc_fw = arg; 236dd08ebf6SMatthew Brost 237dd08ebf6SMatthew Brost if (!xe_uc_fw_is_available(uc_fw)) 238dd08ebf6SMatthew Brost return; 239dd08ebf6SMatthew Brost 240dd08ebf6SMatthew Brost xe_bo_unpin_map_no_vm(uc_fw->bo); 241dd08ebf6SMatthew Brost xe_uc_fw_change_status(uc_fw, XE_UC_FIRMWARE_SELECTED); 242dd08ebf6SMatthew Brost } 243dd08ebf6SMatthew Brost 24499c821b0SMatthew Brost static void guc_read_css_info(struct xe_uc_fw *uc_fw, struct uc_css_header *css) 24599c821b0SMatthew Brost { 24699c821b0SMatthew Brost struct xe_gt *gt = uc_fw_to_gt(uc_fw); 24799c821b0SMatthew Brost struct xe_guc *guc = >->uc.guc; 24899c821b0SMatthew Brost 24999c821b0SMatthew Brost XE_BUG_ON(uc_fw->type != XE_UC_FW_TYPE_GUC); 25099c821b0SMatthew Brost XE_WARN_ON(uc_fw->major_ver_found < 70); 25199c821b0SMatthew Brost 25299c821b0SMatthew Brost if (uc_fw->major_ver_found > 70 || uc_fw->minor_ver_found >= 6) { 25399c821b0SMatthew Brost /* v70.6.0 adds CSS header support */ 25499c821b0SMatthew Brost guc->submission_state.version.major = 25599c821b0SMatthew Brost FIELD_GET(CSS_SW_VERSION_UC_MAJOR, 25699c821b0SMatthew Brost css->submission_version); 25799c821b0SMatthew Brost guc->submission_state.version.minor = 25899c821b0SMatthew Brost FIELD_GET(CSS_SW_VERSION_UC_MINOR, 25999c821b0SMatthew Brost css->submission_version); 26099c821b0SMatthew Brost guc->submission_state.version.patch = 26199c821b0SMatthew Brost FIELD_GET(CSS_SW_VERSION_UC_PATCH, 26299c821b0SMatthew Brost css->submission_version); 26399c821b0SMatthew Brost } else if (uc_fw->minor_ver_found >= 3) { 26499c821b0SMatthew Brost /* v70.3.0 introduced v1.1.0 */ 26599c821b0SMatthew Brost guc->submission_state.version.major = 1; 26699c821b0SMatthew Brost guc->submission_state.version.minor = 1; 26799c821b0SMatthew Brost guc->submission_state.version.patch = 0; 26899c821b0SMatthew Brost } else { 26999c821b0SMatthew Brost /* v70.0.0 introduced v1.0.0 */ 27099c821b0SMatthew Brost guc->submission_state.version.major = 1; 27199c821b0SMatthew Brost guc->submission_state.version.minor = 0; 27299c821b0SMatthew Brost guc->submission_state.version.patch = 0; 27399c821b0SMatthew Brost } 27499c821b0SMatthew Brost 27599c821b0SMatthew Brost uc_fw->private_data_size = css->private_data_size; 27699c821b0SMatthew Brost } 27799c821b0SMatthew Brost 278ad55ead7SLucas De Marchi static int uc_fw_check_version_requirements(struct xe_uc_fw *uc_fw) 279ad55ead7SLucas De Marchi { 280ad55ead7SLucas De Marchi struct xe_device *xe = uc_fw_to_xe(uc_fw); 281ad55ead7SLucas De Marchi 282ad55ead7SLucas De Marchi /* Driver has no requirement on any version, any is good. */ 283ad55ead7SLucas De Marchi if (!uc_fw->major_ver_wanted) 284ad55ead7SLucas De Marchi return 0; 285ad55ead7SLucas De Marchi 286ad55ead7SLucas De Marchi /* 287ad55ead7SLucas De Marchi * If full version is required, both major and minor should match. 288ad55ead7SLucas De Marchi * Otherwise, at least the major version. 289ad55ead7SLucas De Marchi */ 290ad55ead7SLucas De Marchi if (uc_fw->major_ver_wanted != uc_fw->major_ver_found || 291ad55ead7SLucas De Marchi (uc_fw->full_ver_required && 292ad55ead7SLucas De Marchi uc_fw->minor_ver_wanted != uc_fw->minor_ver_found)) { 293ad55ead7SLucas De Marchi drm_notice(&xe->drm, "%s firmware %s: unexpected version: %u.%u != %u.%u\n", 294ad55ead7SLucas De Marchi xe_uc_fw_type_repr(uc_fw->type), uc_fw->path, 295ad55ead7SLucas De Marchi uc_fw->major_ver_found, uc_fw->minor_ver_found, 296ad55ead7SLucas De Marchi uc_fw->major_ver_wanted, uc_fw->minor_ver_wanted); 297ad55ead7SLucas De Marchi goto fail; 298ad55ead7SLucas De Marchi } 299ad55ead7SLucas De Marchi 300ad55ead7SLucas De Marchi if (uc_fw->minor_ver_wanted > uc_fw->minor_ver_found) { 301ad55ead7SLucas De Marchi drm_notice(&xe->drm, "%s firmware (%u.%u) is recommended, but only (%u.%u) was found in %s\n", 302ad55ead7SLucas De Marchi xe_uc_fw_type_repr(uc_fw->type), 303ad55ead7SLucas De Marchi uc_fw->major_ver_wanted, uc_fw->minor_ver_wanted, 304ad55ead7SLucas De Marchi uc_fw->major_ver_found, uc_fw->minor_ver_found, 305ad55ead7SLucas De Marchi uc_fw->path); 306ad55ead7SLucas De Marchi drm_info(&xe->drm, "Consider updating your linux-firmware pkg or downloading from %s\n", 307ad55ead7SLucas De Marchi XE_UC_FIRMWARE_URL); 308ad55ead7SLucas De Marchi } 309ad55ead7SLucas De Marchi 310ad55ead7SLucas De Marchi return 0; 311ad55ead7SLucas De Marchi 312ad55ead7SLucas De Marchi fail: 313ad55ead7SLucas De Marchi if (xe_uc_fw_is_overridden(uc_fw)) 314ad55ead7SLucas De Marchi return 0; 315ad55ead7SLucas De Marchi 316ad55ead7SLucas De Marchi return -ENOEXEC; 317ad55ead7SLucas De Marchi } 318ad55ead7SLucas De Marchi 319dd08ebf6SMatthew Brost int xe_uc_fw_init(struct xe_uc_fw *uc_fw) 320dd08ebf6SMatthew Brost { 321dd08ebf6SMatthew Brost struct xe_device *xe = uc_fw_to_xe(uc_fw); 322dd08ebf6SMatthew Brost struct xe_gt *gt = uc_fw_to_gt(uc_fw); 323dd08ebf6SMatthew Brost struct device *dev = xe->drm.dev; 324dd08ebf6SMatthew Brost const struct firmware *fw = NULL; 325dd08ebf6SMatthew Brost struct uc_css_header *css; 326dd08ebf6SMatthew Brost struct xe_bo *obj; 327dd08ebf6SMatthew Brost size_t size; 328dd08ebf6SMatthew Brost int err; 329dd08ebf6SMatthew Brost 330dd08ebf6SMatthew Brost /* 331dd08ebf6SMatthew Brost * we use FIRMWARE_UNINITIALIZED to detect checks against uc_fw->status 332dd08ebf6SMatthew Brost * before we're looked at the HW caps to see if we have uc support 333dd08ebf6SMatthew Brost */ 334dd08ebf6SMatthew Brost BUILD_BUG_ON(XE_UC_FIRMWARE_UNINITIALIZED); 335dd08ebf6SMatthew Brost XE_BUG_ON(uc_fw->status); 336dd08ebf6SMatthew Brost XE_BUG_ON(uc_fw->path); 337dd08ebf6SMatthew Brost 338dd08ebf6SMatthew Brost uc_fw_auto_select(xe, uc_fw); 339dd08ebf6SMatthew Brost xe_uc_fw_change_status(uc_fw, uc_fw->path ? *uc_fw->path ? 340dd08ebf6SMatthew Brost XE_UC_FIRMWARE_SELECTED : 341dd08ebf6SMatthew Brost XE_UC_FIRMWARE_DISABLED : 342dd08ebf6SMatthew Brost XE_UC_FIRMWARE_NOT_SUPPORTED); 343dd08ebf6SMatthew Brost 344dd08ebf6SMatthew Brost /* Transform no huc in the list into firmware disabled */ 345dd08ebf6SMatthew Brost if (uc_fw->type == XE_UC_FW_TYPE_HUC && !xe_uc_fw_is_supported(uc_fw)) { 346dd08ebf6SMatthew Brost xe_uc_fw_change_status(uc_fw, XE_UC_FIRMWARE_DISABLED); 347dd08ebf6SMatthew Brost err = -ENOPKG; 348dd08ebf6SMatthew Brost return err; 349dd08ebf6SMatthew Brost } 350dd08ebf6SMatthew Brost err = request_firmware(&fw, uc_fw->path, dev); 351dd08ebf6SMatthew Brost if (err) 352dd08ebf6SMatthew Brost goto fail; 353dd08ebf6SMatthew Brost 354dd08ebf6SMatthew Brost /* Check the size of the blob before examining buffer contents */ 355dd08ebf6SMatthew Brost if (unlikely(fw->size < sizeof(struct uc_css_header))) { 356dd08ebf6SMatthew Brost drm_warn(&xe->drm, "%s firmware %s: invalid size: %zu < %zu\n", 357dd08ebf6SMatthew Brost xe_uc_fw_type_repr(uc_fw->type), uc_fw->path, 358dd08ebf6SMatthew Brost fw->size, sizeof(struct uc_css_header)); 359dd08ebf6SMatthew Brost err = -ENODATA; 360dd08ebf6SMatthew Brost goto fail; 361dd08ebf6SMatthew Brost } 362dd08ebf6SMatthew Brost 363dd08ebf6SMatthew Brost css = (struct uc_css_header *)fw->data; 364dd08ebf6SMatthew Brost 365dd08ebf6SMatthew Brost /* Check integrity of size values inside CSS header */ 366dd08ebf6SMatthew Brost size = (css->header_size_dw - css->key_size_dw - css->modulus_size_dw - 367dd08ebf6SMatthew Brost css->exponent_size_dw) * sizeof(u32); 368dd08ebf6SMatthew Brost if (unlikely(size != sizeof(struct uc_css_header))) { 369dd08ebf6SMatthew Brost drm_warn(&xe->drm, 370dd08ebf6SMatthew Brost "%s firmware %s: unexpected header size: %zu != %zu\n", 371dd08ebf6SMatthew Brost xe_uc_fw_type_repr(uc_fw->type), uc_fw->path, 372dd08ebf6SMatthew Brost fw->size, sizeof(struct uc_css_header)); 373dd08ebf6SMatthew Brost err = -EPROTO; 374dd08ebf6SMatthew Brost goto fail; 375dd08ebf6SMatthew Brost } 376dd08ebf6SMatthew Brost 377dd08ebf6SMatthew Brost /* uCode size must calculated from other sizes */ 378dd08ebf6SMatthew Brost uc_fw->ucode_size = (css->size_dw - css->header_size_dw) * sizeof(u32); 379dd08ebf6SMatthew Brost 380dd08ebf6SMatthew Brost /* now RSA */ 381dd08ebf6SMatthew Brost uc_fw->rsa_size = css->key_size_dw * sizeof(u32); 382dd08ebf6SMatthew Brost 383dd08ebf6SMatthew Brost /* At least, it should have header, uCode and RSA. Size of all three. */ 384dd08ebf6SMatthew Brost size = sizeof(struct uc_css_header) + uc_fw->ucode_size + 385dd08ebf6SMatthew Brost uc_fw->rsa_size; 386dd08ebf6SMatthew Brost if (unlikely(fw->size < size)) { 387dd08ebf6SMatthew Brost drm_warn(&xe->drm, "%s firmware %s: invalid size: %zu < %zu\n", 388dd08ebf6SMatthew Brost xe_uc_fw_type_repr(uc_fw->type), uc_fw->path, 389dd08ebf6SMatthew Brost fw->size, size); 390dd08ebf6SMatthew Brost err = -ENOEXEC; 391dd08ebf6SMatthew Brost goto fail; 392dd08ebf6SMatthew Brost } 393dd08ebf6SMatthew Brost 394dd08ebf6SMatthew Brost /* Get version numbers from the CSS header */ 395dd08ebf6SMatthew Brost uc_fw->major_ver_found = FIELD_GET(CSS_SW_VERSION_UC_MAJOR, 396dd08ebf6SMatthew Brost css->sw_version); 397dd08ebf6SMatthew Brost uc_fw->minor_ver_found = FIELD_GET(CSS_SW_VERSION_UC_MINOR, 398dd08ebf6SMatthew Brost css->sw_version); 399dd08ebf6SMatthew Brost 40061e72e77SLucas De Marchi drm_info(&xe->drm, "Using %s firmware (%u.%u) from %s\n", 40161e72e77SLucas De Marchi xe_uc_fw_type_repr(uc_fw->type), 40261e72e77SLucas De Marchi uc_fw->major_ver_found, uc_fw->minor_ver_found, 40361e72e77SLucas De Marchi uc_fw->path); 40461e72e77SLucas De Marchi 405ad55ead7SLucas De Marchi err = uc_fw_check_version_requirements(uc_fw); 406ad55ead7SLucas De Marchi if (err) 407dd08ebf6SMatthew Brost goto fail; 408dd08ebf6SMatthew Brost 409dd08ebf6SMatthew Brost if (uc_fw->type == XE_UC_FW_TYPE_GUC) 41099c821b0SMatthew Brost guc_read_css_info(uc_fw, css); 411dd08ebf6SMatthew Brost 412dd08ebf6SMatthew Brost obj = xe_bo_create_from_data(xe, gt, fw->data, fw->size, 413dd08ebf6SMatthew Brost ttm_bo_type_kernel, 414dd08ebf6SMatthew Brost XE_BO_CREATE_VRAM_IF_DGFX(gt) | 415dd08ebf6SMatthew Brost XE_BO_CREATE_GGTT_BIT); 416dd08ebf6SMatthew Brost if (IS_ERR(obj)) { 417dd08ebf6SMatthew Brost drm_notice(&xe->drm, "%s firmware %s: failed to create / populate bo", 418dd08ebf6SMatthew Brost xe_uc_fw_type_repr(uc_fw->type), uc_fw->path); 419dd08ebf6SMatthew Brost err = PTR_ERR(obj); 420dd08ebf6SMatthew Brost goto fail; 421dd08ebf6SMatthew Brost } 422dd08ebf6SMatthew Brost 423dd08ebf6SMatthew Brost uc_fw->bo = obj; 424dd08ebf6SMatthew Brost uc_fw->size = fw->size; 425dd08ebf6SMatthew Brost xe_uc_fw_change_status(uc_fw, XE_UC_FIRMWARE_AVAILABLE); 426dd08ebf6SMatthew Brost 427dd08ebf6SMatthew Brost release_firmware(fw); 428dd08ebf6SMatthew Brost 429dd08ebf6SMatthew Brost err = drmm_add_action_or_reset(&xe->drm, uc_fw_fini, uc_fw); 430dd08ebf6SMatthew Brost if (err) 431dd08ebf6SMatthew Brost return err; 432dd08ebf6SMatthew Brost 433dd08ebf6SMatthew Brost return 0; 434dd08ebf6SMatthew Brost 435dd08ebf6SMatthew Brost fail: 436dd08ebf6SMatthew Brost xe_uc_fw_change_status(uc_fw, err == -ENOENT ? 437dd08ebf6SMatthew Brost XE_UC_FIRMWARE_MISSING : 438dd08ebf6SMatthew Brost XE_UC_FIRMWARE_ERROR); 439dd08ebf6SMatthew Brost 440dd08ebf6SMatthew Brost drm_notice(&xe->drm, "%s firmware %s: fetch failed with error %d\n", 441dd08ebf6SMatthew Brost xe_uc_fw_type_repr(uc_fw->type), uc_fw->path, err); 442dd08ebf6SMatthew Brost drm_info(&xe->drm, "%s firmware(s) can be downloaded from %s\n", 443dd08ebf6SMatthew Brost xe_uc_fw_type_repr(uc_fw->type), XE_UC_FIRMWARE_URL); 444dd08ebf6SMatthew Brost 445dd08ebf6SMatthew Brost release_firmware(fw); /* OK even if fw is NULL */ 446dd08ebf6SMatthew Brost return err; 447dd08ebf6SMatthew Brost } 448dd08ebf6SMatthew Brost 449dd08ebf6SMatthew Brost static u32 uc_fw_ggtt_offset(struct xe_uc_fw *uc_fw) 450dd08ebf6SMatthew Brost { 451dd08ebf6SMatthew Brost return xe_bo_ggtt_addr(uc_fw->bo); 452dd08ebf6SMatthew Brost } 453dd08ebf6SMatthew Brost 454dd08ebf6SMatthew Brost static int uc_fw_xfer(struct xe_uc_fw *uc_fw, u32 offset, u32 dma_flags) 455dd08ebf6SMatthew Brost { 456dd08ebf6SMatthew Brost struct xe_device *xe = uc_fw_to_xe(uc_fw); 457dd08ebf6SMatthew Brost struct xe_gt *gt = uc_fw_to_gt(uc_fw); 4587aaec3a6SRodrigo Vivi u32 src_offset, dma_ctrl; 459dd08ebf6SMatthew Brost int ret; 460dd08ebf6SMatthew Brost 461dd08ebf6SMatthew Brost xe_force_wake_assert_held(gt_to_fw(gt), XE_FW_GT); 462dd08ebf6SMatthew Brost 463dd08ebf6SMatthew Brost /* Set the source address for the uCode */ 464dd08ebf6SMatthew Brost src_offset = uc_fw_ggtt_offset(uc_fw); 465dd08ebf6SMatthew Brost xe_mmio_write32(gt, DMA_ADDR_0_LOW.reg, lower_32_bits(src_offset)); 466dd08ebf6SMatthew Brost xe_mmio_write32(gt, DMA_ADDR_0_HIGH.reg, upper_32_bits(src_offset)); 467dd08ebf6SMatthew Brost 468dd08ebf6SMatthew Brost /* Set the DMA destination */ 469dd08ebf6SMatthew Brost xe_mmio_write32(gt, DMA_ADDR_1_LOW.reg, offset); 470dd08ebf6SMatthew Brost xe_mmio_write32(gt, DMA_ADDR_1_HIGH.reg, DMA_ADDRESS_SPACE_WOPCM); 471dd08ebf6SMatthew Brost 472dd08ebf6SMatthew Brost /* 473dd08ebf6SMatthew Brost * Set the transfer size. The header plus uCode will be copied to WOPCM 474dd08ebf6SMatthew Brost * via DMA, excluding any other components 475dd08ebf6SMatthew Brost */ 476dd08ebf6SMatthew Brost xe_mmio_write32(gt, DMA_COPY_SIZE.reg, 477dd08ebf6SMatthew Brost sizeof(struct uc_css_header) + uc_fw->ucode_size); 478dd08ebf6SMatthew Brost 479dd08ebf6SMatthew Brost /* Start the DMA */ 480dd08ebf6SMatthew Brost xe_mmio_write32(gt, DMA_CTRL.reg, 481dd08ebf6SMatthew Brost _MASKED_BIT_ENABLE(dma_flags | START_DMA)); 482dd08ebf6SMatthew Brost 483dd08ebf6SMatthew Brost /* Wait for DMA to finish */ 4847dc9b92dSRodrigo Vivi ret = xe_mmio_wait32(gt, DMA_CTRL.reg, 0, START_DMA, 100000, &dma_ctrl, 4857dc9b92dSRodrigo Vivi false); 486dd08ebf6SMatthew Brost if (ret) 487dd08ebf6SMatthew Brost drm_err(&xe->drm, "DMA for %s fw failed, DMA_CTRL=%u\n", 4887aaec3a6SRodrigo Vivi xe_uc_fw_type_repr(uc_fw->type), dma_ctrl); 489dd08ebf6SMatthew Brost 490dd08ebf6SMatthew Brost /* Disable the bits once DMA is over */ 491dd08ebf6SMatthew Brost xe_mmio_write32(gt, DMA_CTRL.reg, _MASKED_BIT_DISABLE(dma_flags)); 492dd08ebf6SMatthew Brost 493dd08ebf6SMatthew Brost return ret; 494dd08ebf6SMatthew Brost } 495dd08ebf6SMatthew Brost 496dd08ebf6SMatthew Brost int xe_uc_fw_upload(struct xe_uc_fw *uc_fw, u32 offset, u32 dma_flags) 497dd08ebf6SMatthew Brost { 498dd08ebf6SMatthew Brost struct xe_device *xe = uc_fw_to_xe(uc_fw); 499dd08ebf6SMatthew Brost int err; 500dd08ebf6SMatthew Brost 501dd08ebf6SMatthew Brost /* make sure the status was cleared the last time we reset the uc */ 502dd08ebf6SMatthew Brost XE_BUG_ON(xe_uc_fw_is_loaded(uc_fw)); 503dd08ebf6SMatthew Brost 504dd08ebf6SMatthew Brost if (!xe_uc_fw_is_loadable(uc_fw)) 505dd08ebf6SMatthew Brost return -ENOEXEC; 506dd08ebf6SMatthew Brost 507dd08ebf6SMatthew Brost /* Call custom loader */ 508dd08ebf6SMatthew Brost err = uc_fw_xfer(uc_fw, offset, dma_flags); 509dd08ebf6SMatthew Brost if (err) 510dd08ebf6SMatthew Brost goto fail; 511dd08ebf6SMatthew Brost 512dd08ebf6SMatthew Brost xe_uc_fw_change_status(uc_fw, XE_UC_FIRMWARE_TRANSFERRED); 513dd08ebf6SMatthew Brost return 0; 514dd08ebf6SMatthew Brost 515dd08ebf6SMatthew Brost fail: 516dd08ebf6SMatthew Brost drm_err(&xe->drm, "Failed to load %s firmware %s (%d)\n", 517dd08ebf6SMatthew Brost xe_uc_fw_type_repr(uc_fw->type), uc_fw->path, 518dd08ebf6SMatthew Brost err); 519dd08ebf6SMatthew Brost xe_uc_fw_change_status(uc_fw, XE_UC_FIRMWARE_LOAD_FAIL); 520dd08ebf6SMatthew Brost return err; 521dd08ebf6SMatthew Brost } 522dd08ebf6SMatthew Brost 523dd08ebf6SMatthew Brost 524dd08ebf6SMatthew Brost void xe_uc_fw_print(struct xe_uc_fw *uc_fw, struct drm_printer *p) 525dd08ebf6SMatthew Brost { 526dd08ebf6SMatthew Brost drm_printf(p, "%s firmware: %s\n", 527dd08ebf6SMatthew Brost xe_uc_fw_type_repr(uc_fw->type), uc_fw->path); 528dd08ebf6SMatthew Brost drm_printf(p, "\tstatus: %s\n", 529dd08ebf6SMatthew Brost xe_uc_fw_status_repr(uc_fw->status)); 530dd08ebf6SMatthew Brost drm_printf(p, "\tversion: wanted %u.%u, found %u.%u\n", 531dd08ebf6SMatthew Brost uc_fw->major_ver_wanted, uc_fw->minor_ver_wanted, 532dd08ebf6SMatthew Brost uc_fw->major_ver_found, uc_fw->minor_ver_found); 533dd08ebf6SMatthew Brost drm_printf(p, "\tuCode: %u bytes\n", uc_fw->ucode_size); 534dd08ebf6SMatthew Brost drm_printf(p, "\tRSA: %u bytes\n", uc_fw->rsa_size); 53599c821b0SMatthew Brost 53699c821b0SMatthew Brost if (uc_fw->type == XE_UC_FW_TYPE_GUC) { 53799c821b0SMatthew Brost struct xe_gt *gt = uc_fw_to_gt(uc_fw); 53899c821b0SMatthew Brost struct xe_guc *guc = >->uc.guc; 53999c821b0SMatthew Brost 54099c821b0SMatthew Brost drm_printf(p, "\tSubmit version: %u.%u.%u\n", 54199c821b0SMatthew Brost guc->submission_state.version.major, 54299c821b0SMatthew Brost guc->submission_state.version.minor, 54399c821b0SMatthew Brost guc->submission_state.version.patch); 54499c821b0SMatthew Brost } 545dd08ebf6SMatthew Brost } 546