linux/drivers/gpu/drm/i915/intel_uc_fw.c
<<
>>
Prefs
   1/*
   2 * Copyright © 2016-2017 Intel Corporation
   3 *
   4 * Permission is hereby granted, free of charge, to any person obtaining a
   5 * copy of this software and associated documentation files (the "Software"),
   6 * to deal in the Software without restriction, including without limitation
   7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
   8 * and/or sell copies of the Software, and to permit persons to whom the
   9 * Software is furnished to do so, subject to the following conditions:
  10 *
  11 * The above copyright notice and this permission notice (including the next
  12 * paragraph) shall be included in all copies or substantial portions of the
  13 * Software.
  14 *
  15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
  18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
  21 * IN THE SOFTWARE.
  22 *
  23 */
  24
  25#include <linux/firmware.h>
  26#include <drm/drm_print.h>
  27
  28#include "intel_uc_fw.h"
  29#include "i915_drv.h"
  30
  31/**
  32 * intel_uc_fw_fetch - fetch uC firmware
  33 *
  34 * @dev_priv: device private
  35 * @uc_fw: uC firmware
  36 *
  37 * Fetch uC firmware into GEM obj.
  38 */
  39void intel_uc_fw_fetch(struct drm_i915_private *dev_priv,
  40                       struct intel_uc_fw *uc_fw)
  41{
  42        struct pci_dev *pdev = dev_priv->drm.pdev;
  43        struct drm_i915_gem_object *obj;
  44        const struct firmware *fw = NULL;
  45        struct uc_css_header *css;
  46        size_t size;
  47        int err;
  48
  49        DRM_DEBUG_DRIVER("%s fw fetch %s\n",
  50                         intel_uc_fw_type_repr(uc_fw->type), uc_fw->path);
  51
  52        if (!uc_fw->path)
  53                return;
  54
  55        uc_fw->fetch_status = INTEL_UC_FIRMWARE_PENDING;
  56        DRM_DEBUG_DRIVER("%s fw fetch %s\n",
  57                         intel_uc_fw_type_repr(uc_fw->type),
  58                         intel_uc_fw_status_repr(uc_fw->fetch_status));
  59
  60        err = request_firmware(&fw, uc_fw->path, &pdev->dev);
  61        if (err) {
  62                DRM_DEBUG_DRIVER("%s fw request_firmware err=%d\n",
  63                                 intel_uc_fw_type_repr(uc_fw->type), err);
  64                goto fail;
  65        }
  66
  67        DRM_DEBUG_DRIVER("%s fw size %zu ptr %p\n",
  68                         intel_uc_fw_type_repr(uc_fw->type), fw->size, fw);
  69
  70        /* Check the size of the blob before examining buffer contents */
  71        if (fw->size < sizeof(struct uc_css_header)) {
  72                DRM_WARN("%s: Unexpected firmware size (%zu, min %zu)\n",
  73                         intel_uc_fw_type_repr(uc_fw->type),
  74                         fw->size, sizeof(struct uc_css_header));
  75                err = -ENODATA;
  76                goto fail;
  77        }
  78
  79        css = (struct uc_css_header *)fw->data;
  80
  81        /* Firmware bits always start from header */
  82        uc_fw->header_offset = 0;
  83        uc_fw->header_size = (css->header_size_dw - css->modulus_size_dw -
  84                              css->key_size_dw - css->exponent_size_dw) *
  85                             sizeof(u32);
  86
  87        if (uc_fw->header_size != sizeof(struct uc_css_header)) {
  88                DRM_WARN("%s: Mismatched firmware header definition\n",
  89                         intel_uc_fw_type_repr(uc_fw->type));
  90                err = -ENOEXEC;
  91                goto fail;
  92        }
  93
  94        /* then, uCode */
  95        uc_fw->ucode_offset = uc_fw->header_offset + uc_fw->header_size;
  96        uc_fw->ucode_size = (css->size_dw - css->header_size_dw) * sizeof(u32);
  97
  98        /* now RSA */
  99        if (css->key_size_dw != UOS_RSA_SCRATCH_COUNT) {
 100                DRM_WARN("%s: Mismatched firmware RSA key size (%u)\n",
 101                         intel_uc_fw_type_repr(uc_fw->type), css->key_size_dw);
 102                err = -ENOEXEC;
 103                goto fail;
 104        }
 105        uc_fw->rsa_offset = uc_fw->ucode_offset + uc_fw->ucode_size;
 106        uc_fw->rsa_size = css->key_size_dw * sizeof(u32);
 107
 108        /* At least, it should have header, uCode and RSA. Size of all three. */
 109        size = uc_fw->header_size + uc_fw->ucode_size + uc_fw->rsa_size;
 110        if (fw->size < size) {
 111                DRM_WARN("%s: Truncated firmware (%zu, expected %zu)\n",
 112                         intel_uc_fw_type_repr(uc_fw->type), fw->size, size);
 113                err = -ENOEXEC;
 114                goto fail;
 115        }
 116
 117        /*
 118         * The GuC firmware image has the version number embedded at a
 119         * well-known offset within the firmware blob; note that major / minor
 120         * version are TWO bytes each (i.e. u16), although all pointers and
 121         * offsets are defined in terms of bytes (u8).
 122         */
 123        switch (uc_fw->type) {
 124        case INTEL_UC_FW_TYPE_GUC:
 125                uc_fw->major_ver_found = css->guc.sw_version >> 16;
 126                uc_fw->minor_ver_found = css->guc.sw_version & 0xFFFF;
 127                break;
 128
 129        case INTEL_UC_FW_TYPE_HUC:
 130                uc_fw->major_ver_found = css->huc.sw_version >> 16;
 131                uc_fw->minor_ver_found = css->huc.sw_version & 0xFFFF;
 132                break;
 133
 134        default:
 135                MISSING_CASE(uc_fw->type);
 136                break;
 137        }
 138
 139        DRM_DEBUG_DRIVER("%s fw version %u.%u (wanted %u.%u)\n",
 140                         intel_uc_fw_type_repr(uc_fw->type),
 141                         uc_fw->major_ver_found, uc_fw->minor_ver_found,
 142                         uc_fw->major_ver_wanted, uc_fw->minor_ver_wanted);
 143
 144        if (uc_fw->major_ver_wanted == 0 && uc_fw->minor_ver_wanted == 0) {
 145                DRM_NOTE("%s: Skipping firmware version check\n",
 146                         intel_uc_fw_type_repr(uc_fw->type));
 147        } else if (uc_fw->major_ver_found != uc_fw->major_ver_wanted ||
 148                   uc_fw->minor_ver_found < uc_fw->minor_ver_wanted) {
 149                DRM_NOTE("%s: Wrong firmware version (%u.%u, required %u.%u)\n",
 150                         intel_uc_fw_type_repr(uc_fw->type),
 151                         uc_fw->major_ver_found, uc_fw->minor_ver_found,
 152                         uc_fw->major_ver_wanted, uc_fw->minor_ver_wanted);
 153                err = -ENOEXEC;
 154                goto fail;
 155        }
 156
 157        obj = i915_gem_object_create_from_data(dev_priv, fw->data, fw->size);
 158        if (IS_ERR(obj)) {
 159                err = PTR_ERR(obj);
 160                DRM_DEBUG_DRIVER("%s fw object_create err=%d\n",
 161                                 intel_uc_fw_type_repr(uc_fw->type), err);
 162                goto fail;
 163        }
 164
 165        uc_fw->obj = obj;
 166        uc_fw->size = fw->size;
 167        uc_fw->fetch_status = INTEL_UC_FIRMWARE_SUCCESS;
 168        DRM_DEBUG_DRIVER("%s fw fetch %s\n",
 169                         intel_uc_fw_type_repr(uc_fw->type),
 170                         intel_uc_fw_status_repr(uc_fw->fetch_status));
 171
 172        release_firmware(fw);
 173        return;
 174
 175fail:
 176        uc_fw->fetch_status = INTEL_UC_FIRMWARE_FAIL;
 177        DRM_DEBUG_DRIVER("%s fw fetch %s\n",
 178                         intel_uc_fw_type_repr(uc_fw->type),
 179                         intel_uc_fw_status_repr(uc_fw->fetch_status));
 180
 181        DRM_WARN("%s: Failed to fetch firmware %s (error %d)\n",
 182                 intel_uc_fw_type_repr(uc_fw->type), uc_fw->path, err);
 183        DRM_INFO("%s: Firmware can be downloaded from %s\n",
 184                 intel_uc_fw_type_repr(uc_fw->type), INTEL_UC_FIRMWARE_URL);
 185
 186        release_firmware(fw);           /* OK even if fw is NULL */
 187}
 188
 189/**
 190 * intel_uc_fw_upload - load uC firmware using custom loader
 191 * @uc_fw: uC firmware
 192 * @xfer: custom uC firmware loader function
 193 *
 194 * Loads uC firmware using custom loader and updates internal flags.
 195 *
 196 * Return: 0 on success, non-zero on failure.
 197 */
 198int intel_uc_fw_upload(struct intel_uc_fw *uc_fw,
 199                       int (*xfer)(struct intel_uc_fw *uc_fw,
 200                                   struct i915_vma *vma))
 201{
 202        struct i915_vma *vma;
 203        u32 ggtt_pin_bias;
 204        int err;
 205
 206        DRM_DEBUG_DRIVER("%s fw load %s\n",
 207                         intel_uc_fw_type_repr(uc_fw->type), uc_fw->path);
 208
 209        if (uc_fw->fetch_status != INTEL_UC_FIRMWARE_SUCCESS)
 210                return -ENOEXEC;
 211
 212        uc_fw->load_status = INTEL_UC_FIRMWARE_PENDING;
 213        DRM_DEBUG_DRIVER("%s fw load %s\n",
 214                         intel_uc_fw_type_repr(uc_fw->type),
 215                         intel_uc_fw_status_repr(uc_fw->load_status));
 216
 217        /* Pin object with firmware */
 218        err = i915_gem_object_set_to_gtt_domain(uc_fw->obj, false);
 219        if (err) {
 220                DRM_DEBUG_DRIVER("%s fw set-domain err=%d\n",
 221                                 intel_uc_fw_type_repr(uc_fw->type), err);
 222                goto fail;
 223        }
 224
 225        ggtt_pin_bias = to_i915(uc_fw->obj->base.dev)->guc.ggtt_pin_bias;
 226        vma = i915_gem_object_ggtt_pin(uc_fw->obj, NULL, 0, 0,
 227                                       PIN_OFFSET_BIAS | ggtt_pin_bias);
 228        if (IS_ERR(vma)) {
 229                err = PTR_ERR(vma);
 230                DRM_DEBUG_DRIVER("%s fw ggtt-pin err=%d\n",
 231                                 intel_uc_fw_type_repr(uc_fw->type), err);
 232                goto fail;
 233        }
 234
 235        /* Call custom loader */
 236        err = xfer(uc_fw, vma);
 237
 238        /*
 239         * We keep the object pages for reuse during resume. But we can unpin it
 240         * now that DMA has completed, so it doesn't continue to take up space.
 241         */
 242        i915_vma_unpin(vma);
 243
 244        if (err)
 245                goto fail;
 246
 247        uc_fw->load_status = INTEL_UC_FIRMWARE_SUCCESS;
 248        DRM_DEBUG_DRIVER("%s fw load %s\n",
 249                         intel_uc_fw_type_repr(uc_fw->type),
 250                         intel_uc_fw_status_repr(uc_fw->load_status));
 251
 252        DRM_INFO("%s: Loaded firmware %s (version %u.%u)\n",
 253                 intel_uc_fw_type_repr(uc_fw->type),
 254                 uc_fw->path,
 255                 uc_fw->major_ver_found, uc_fw->minor_ver_found);
 256
 257        return 0;
 258
 259fail:
 260        uc_fw->load_status = INTEL_UC_FIRMWARE_FAIL;
 261        DRM_DEBUG_DRIVER("%s fw load %s\n",
 262                         intel_uc_fw_type_repr(uc_fw->type),
 263                         intel_uc_fw_status_repr(uc_fw->load_status));
 264
 265        DRM_WARN("%s: Failed to load firmware %s (error %d)\n",
 266                 intel_uc_fw_type_repr(uc_fw->type), uc_fw->path, err);
 267
 268        return err;
 269}
 270
 271/**
 272 * intel_uc_fw_fini - cleanup uC firmware
 273 *
 274 * @uc_fw: uC firmware
 275 *
 276 * Cleans up uC firmware by releasing the firmware GEM obj.
 277 */
 278void intel_uc_fw_fini(struct intel_uc_fw *uc_fw)
 279{
 280        struct drm_i915_gem_object *obj;
 281
 282        obj = fetch_and_zero(&uc_fw->obj);
 283        if (obj)
 284                i915_gem_object_put(obj);
 285
 286        uc_fw->fetch_status = INTEL_UC_FIRMWARE_NONE;
 287}
 288
 289/**
 290 * intel_uc_fw_dump - dump information about uC firmware
 291 * @uc_fw: uC firmware
 292 * @p: the &drm_printer
 293 *
 294 * Pretty printer for uC firmware.
 295 */
 296void intel_uc_fw_dump(const struct intel_uc_fw *uc_fw, struct drm_printer *p)
 297{
 298        drm_printf(p, "%s firmware: %s\n",
 299                   intel_uc_fw_type_repr(uc_fw->type), uc_fw->path);
 300        drm_printf(p, "\tstatus: fetch %s, load %s\n",
 301                   intel_uc_fw_status_repr(uc_fw->fetch_status),
 302                   intel_uc_fw_status_repr(uc_fw->load_status));
 303        drm_printf(p, "\tversion: wanted %u.%u, found %u.%u\n",
 304                   uc_fw->major_ver_wanted, uc_fw->minor_ver_wanted,
 305                   uc_fw->major_ver_found, uc_fw->minor_ver_found);
 306        drm_printf(p, "\theader: offset %u, size %u\n",
 307                   uc_fw->header_offset, uc_fw->header_size);
 308        drm_printf(p, "\tuCode: offset %u, size %u\n",
 309                   uc_fw->ucode_offset, uc_fw->ucode_size);
 310        drm_printf(p, "\tRSA: offset %u, size %u\n",
 311                   uc_fw->rsa_offset, uc_fw->rsa_size);
 312}
 313