// SPDX-License-Identifier: MIT /* * Copyright © 2022 Intel Corporation */ #include <linux/bitfield.h> #include <linux/firmware.h> #include <drm/drm_managed.h> #include "regs/xe_guc_regs.h" #include "xe_bo.h" #include "xe_device_types.h" #include "xe_force_wake.h" #include "xe_gsc.h" #include "xe_gt.h" #include "xe_gt_printk.h" #include "xe_map.h" #include "xe_mmio.h" #include "xe_module.h" #include "xe_sriov.h" #include "xe_uc_fw.h" /* * List of required GuC and HuC binaries per-platform. They must be ordered * based on platform, from newer to older. * * Versioning follows the guidelines from * Documentation/driver-api/firmware/firmware-usage-guidelines.rst. There is a * distinction for platforms being officially supported by the driver or not. * Platforms not available publicly or not yet officially supported by the * driver (under force-probe), use the mmp_ver(): the firmware autoselect logic * will select the firmware from disk with filename that matches the full * "mpp version", i.e. major.minor.patch. mmp_ver() should only be used for * this case. * * For platforms officially supported by the driver, the filename always only * ever contains the major version (GuC) or no version at all (HuC). * * After loading the file, the driver parses the versions embedded in the blob. * The major version needs to match a major version supported by the driver (if * any). The minor version is also checked and a notice emitted to the log if * the version found is smaller than the version wanted. This is done only for * informational purposes so users may have a chance to upgrade, but the driver * still loads and use the older firmware. * * Examples: * * 1) Platform officially supported by i915 - using Tigerlake as example. * Driver loads the following firmware blobs from disk: * * - i915/tgl_guc_<major>.bin * - i915/tgl_huc.bin * * <major> number for GuC is checked that it matches the version inside * the blob. <minor> version is checked and if smaller than the expected * an info message is emitted about that. * * 1) XE_<FUTUREINTELPLATFORM>, still under require_force_probe. Using * "wipplat" as a short-name. Driver loads the following firmware blobs * from disk: * * - xe/wipplat_guc_<major>.<minor>.<patch>.bin * - xe/wipplat_huc_<major>.<minor>.<patch>.bin * * <major> and <minor> are checked that they match the version inside * the blob. Both of them need to match exactly what the driver is * expecting, otherwise it fails. * * 3) Platform officially supported by xe and out of force-probe. Using * "plat" as a short-name. Except for the different directory, the * behavior is the same as (1). Driver loads the following firmware * blobs from disk: * * - xe/plat_guc_<major>.bin * - xe/plat_huc.bin * * <major> number for GuC is checked that it matches the version inside * the blob. <minor> version is checked and if smaller than the expected * an info message is emitted about that. * * For the platforms already released with a major version, they should never be * removed from the table. Instead new entries with newer versions may be added * before them, so they take precedence. * * TODO: Currently there's no fallback on major version. That's because xe * driver only supports the one major version of each firmware in the table. * This needs to be fixed when the major version of GuC is updated. */ struct uc_fw_entry { … }; struct fw_blobs_by_type { … }; #define XE_GUC_FIRMWARE_DEFS(fw_def, mmp_ver, major_ver) … #define XE_HUC_FIRMWARE_DEFS(fw_def, mmp_ver, no_ver) … /* for the GSC FW we match the compatibility version and not the release one */ #define XE_GSC_FIRMWARE_DEFS(fw_def, major_ver) … #define MAKE_FW_PATH(dir__, uc__, shortname__, version__) … #define fw_filename_mmp_ver(dir_, uc_, shortname_, a, b, c) … #define fw_filename_major_ver(dir_, uc_, shortname_, a, b, c) … #define fw_filename_no_ver(dir_, uc_, shortname_) … #define uc_fw_entry_mmp_ver(dir_, uc_, shortname_, a, b, c) … #define uc_fw_entry_major_ver(dir_, uc_, shortname_, a, b, c) … #define uc_fw_entry_no_ver(dir_, uc_, shortname_) … /* All blobs need to be declared via MODULE_FIRMWARE() */ #define XE_UC_MODULE_FIRMWARE(platform__, fw_filename) … #define XE_UC_FW_ENTRY(platform__, entry__) … XE_GUC_FIRMWARE_DEFS(…) XE_HUC_FIRMWARE_DEFS(…) XE_GSC_FIRMWARE_DEFS(…) static struct xe_gt * __uc_fw_to_gt(struct xe_uc_fw *uc_fw, enum xe_uc_fw_type type) { … } static struct xe_gt *uc_fw_to_gt(struct xe_uc_fw *uc_fw) { … } static struct xe_device *uc_fw_to_xe(struct xe_uc_fw *uc_fw) { … } static void uc_fw_auto_select(struct xe_device *xe, struct xe_uc_fw *uc_fw) { … } static void uc_fw_override(struct xe_uc_fw *uc_fw) { … } /** * xe_uc_fw_copy_rsa - copy fw RSA to buffer * * @uc_fw: uC firmware * @dst: dst buffer * @max_len: max number of bytes to copy * * Return: number of copied bytes. */ size_t xe_uc_fw_copy_rsa(struct xe_uc_fw *uc_fw, void *dst, u32 max_len) { … } static void uc_fw_fini(struct drm_device *drm, void *arg) { … } static int guc_read_css_info(struct xe_uc_fw *uc_fw, struct uc_css_header *css) { … } int xe_uc_fw_check_version_requirements(struct xe_uc_fw *uc_fw) { … } /* Refer to the "CSS-based Firmware Layout" documentation entry for details */ static int parse_css_header(struct xe_uc_fw *uc_fw, const void *fw_data, size_t fw_size) { … } static bool is_cpd_header(const void *data) { … } static u32 entry_offset(const struct gsc_cpd_header_v2 *header, const char *name) { … } /* Refer to the "GSC-based Firmware Layout" documentation entry for details */ static int parse_cpd_header(struct xe_uc_fw *uc_fw, const void *data, size_t size, const char *manifest_entry, const char *css_entry) { … } static int parse_gsc_layout(struct xe_uc_fw *uc_fw, const void *data, size_t size) { … } static int parse_headers(struct xe_uc_fw *uc_fw, const struct firmware *fw) { … } #define print_uc_fw_version(p_, version_, prefix_, ...) … static int uc_fw_request(struct xe_uc_fw *uc_fw, const struct firmware **firmware_p) { … } static void uc_fw_release(const struct firmware *fw) { … } static int uc_fw_copy(struct xe_uc_fw *uc_fw, const void *data, size_t size, u32 flags) { … } int xe_uc_fw_init(struct xe_uc_fw *uc_fw) { … } static u32 uc_fw_ggtt_offset(struct xe_uc_fw *uc_fw) { … } static int uc_fw_xfer(struct xe_uc_fw *uc_fw, u32 offset, u32 dma_flags) { … } int xe_uc_fw_upload(struct xe_uc_fw *uc_fw, u32 offset, u32 dma_flags) { … } static const char *version_type_repr(enum xe_uc_fw_version_types type) { … } void xe_uc_fw_print(struct xe_uc_fw *uc_fw, struct drm_printer *p) { … }