LCOV - code coverage report
Current view: top level - drivers/gpu/drm/i915/gt/uc - intel_uc_fw.c (source / functions) Hit Total Coverage
Test: combined.info Lines: 0 216 0.0 %
Date: 2022-04-01 13:59:58 Functions: 0 12 0.0 %
Branches: 0 127 0.0 %

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

Generated by: LCOV version 1.14