The firmware binary has to be loaded from lmem and the recommendation is to put all other objects in there as well. Note that we don't fall back to system memory if the allocation in lmem fails because all objects are allocated during driver load and if we have issues with lmem at that point something is seriously wrong with the system, so no point in trying to handle it. Cc: Matthew Auld <matthew.auld@intel.com> Cc: Abdiel Janulgue <abdiel.janulgue@linux.intel.com> Cc: Michal Wajdeczko <michal.wajdeczko@intel.com> Cc: Vinay Belgaumkar <vinay.belgaumkar@intel.com> Cc: Radoslaw Szwichtenberg <radoslaw.szwichtenberg@intel.com> Signed-off-by: Daniele Ceraolo Spurio <daniele.ceraolospurio@intel.com> Signed-off-by: Matthew Brost <matthew.brost@intel.com> Reviewed-by: Matthew Brost <matthew.brost@intel.com> Signed-off-by: John Harrison <John.C.Harrison@Intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20210916162819.27848-3-matthew.brost@intel.com
169 lines
4.6 KiB
C
169 lines
4.6 KiB
C
// SPDX-License-Identifier: MIT
|
|
/*
|
|
* Copyright © 2014-2019 Intel Corporation
|
|
*
|
|
* Authors:
|
|
* Vinit Azad <vinit.azad@intel.com>
|
|
* Ben Widawsky <ben@bwidawsk.net>
|
|
* Dave Gordon <david.s.gordon@intel.com>
|
|
* Alex Dai <yu.dai@intel.com>
|
|
*/
|
|
|
|
#include "gt/intel_gt.h"
|
|
#include "intel_guc_fw.h"
|
|
#include "i915_drv.h"
|
|
|
|
static void guc_prepare_xfer(struct intel_uncore *uncore)
|
|
{
|
|
u32 shim_flags = GUC_DISABLE_SRAM_INIT_TO_ZEROES |
|
|
GUC_ENABLE_READ_CACHE_LOGIC |
|
|
GUC_ENABLE_MIA_CACHING |
|
|
GUC_ENABLE_READ_CACHE_FOR_SRAM_DATA |
|
|
GUC_ENABLE_READ_CACHE_FOR_WOPCM_DATA |
|
|
GUC_ENABLE_MIA_CLOCK_GATING;
|
|
|
|
/* Must program this register before loading the ucode with DMA */
|
|
intel_uncore_write(uncore, GUC_SHIM_CONTROL, shim_flags);
|
|
|
|
if (IS_GEN9_LP(uncore->i915))
|
|
intel_uncore_write(uncore, GEN9LP_GT_PM_CONFIG, GT_DOORBELL_ENABLE);
|
|
else
|
|
intel_uncore_write(uncore, GEN9_GT_PM_CONFIG, GT_DOORBELL_ENABLE);
|
|
|
|
if (GRAPHICS_VER(uncore->i915) == 9) {
|
|
/* DOP Clock Gating Enable for GuC clocks */
|
|
intel_uncore_rmw(uncore, GEN7_MISCCPCTL,
|
|
0, GEN8_DOP_CLOCK_GATE_GUC_ENABLE);
|
|
|
|
/* allows for 5us (in 10ns units) before GT can go to RC6 */
|
|
intel_uncore_write(uncore, GUC_ARAT_C6DIS, 0x1FF);
|
|
}
|
|
}
|
|
|
|
/* Copy RSA signature from the fw image to HW for verification */
|
|
static int guc_xfer_rsa(struct intel_uc_fw *guc_fw,
|
|
struct intel_uncore *uncore)
|
|
{
|
|
u32 rsa[UOS_RSA_SCRATCH_COUNT];
|
|
size_t copied;
|
|
int i;
|
|
|
|
copied = intel_uc_fw_copy_rsa(guc_fw, rsa, sizeof(rsa));
|
|
if (copied < sizeof(rsa))
|
|
return -ENOMEM;
|
|
|
|
for (i = 0; i < UOS_RSA_SCRATCH_COUNT; i++)
|
|
intel_uncore_write(uncore, UOS_RSA_SCRATCH(i), rsa[i]);
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* Read the GuC status register (GUC_STATUS) and store it in the
|
|
* specified location; then return a boolean indicating whether
|
|
* the value matches either of two values representing completion
|
|
* of the GuC boot process.
|
|
*
|
|
* This is used for polling the GuC status in a wait_for()
|
|
* loop below.
|
|
*/
|
|
static inline bool guc_ready(struct intel_uncore *uncore, u32 *status)
|
|
{
|
|
u32 val = intel_uncore_read(uncore, GUC_STATUS);
|
|
u32 uk_val = val & GS_UKERNEL_MASK;
|
|
|
|
*status = val;
|
|
return (uk_val == GS_UKERNEL_READY) ||
|
|
((val & GS_MIA_CORE_STATE) && (uk_val == GS_UKERNEL_LAPIC_DONE));
|
|
}
|
|
|
|
static int guc_wait_ucode(struct intel_uncore *uncore)
|
|
{
|
|
u32 status;
|
|
int ret;
|
|
|
|
/*
|
|
* Wait for the GuC to start up.
|
|
* NB: Docs recommend not using the interrupt for completion.
|
|
* Measurements indicate this should take no more than 20ms, so a
|
|
* timeout here indicates that the GuC has failed and is unusable.
|
|
* (Higher levels of the driver may decide to reset the GuC and
|
|
* attempt the ucode load again if this happens.)
|
|
*/
|
|
ret = wait_for(guc_ready(uncore, &status), 100);
|
|
if (ret) {
|
|
struct drm_device *drm = &uncore->i915->drm;
|
|
|
|
drm_dbg(drm, "GuC load failed: status = 0x%08X\n", status);
|
|
drm_dbg(drm, "GuC load failed: status: Reset = %d, "
|
|
"BootROM = 0x%02X, UKernel = 0x%02X, "
|
|
"MIA = 0x%02X, Auth = 0x%02X\n",
|
|
REG_FIELD_GET(GS_MIA_IN_RESET, status),
|
|
REG_FIELD_GET(GS_BOOTROM_MASK, status),
|
|
REG_FIELD_GET(GS_UKERNEL_MASK, status),
|
|
REG_FIELD_GET(GS_MIA_MASK, status),
|
|
REG_FIELD_GET(GS_AUTH_STATUS_MASK, status));
|
|
|
|
if ((status & GS_BOOTROM_MASK) == GS_BOOTROM_RSA_FAILED) {
|
|
drm_dbg(drm, "GuC firmware signature verification failed\n");
|
|
ret = -ENOEXEC;
|
|
}
|
|
|
|
if ((status & GS_UKERNEL_MASK) == GS_UKERNEL_EXCEPTION) {
|
|
drm_dbg(drm, "GuC firmware exception. EIP: %#x\n",
|
|
intel_uncore_read(uncore, SOFT_SCRATCH(13)));
|
|
ret = -ENXIO;
|
|
}
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
/**
|
|
* intel_guc_fw_upload() - load GuC uCode to device
|
|
* @guc: intel_guc structure
|
|
*
|
|
* Called from intel_uc_init_hw() during driver load, resume from sleep and
|
|
* after a GPU reset.
|
|
*
|
|
* The firmware image should have already been fetched into memory, so only
|
|
* check that fetch succeeded, and then transfer the image to the h/w.
|
|
*
|
|
* Return: non-zero code on error
|
|
*/
|
|
int intel_guc_fw_upload(struct intel_guc *guc)
|
|
{
|
|
struct intel_gt *gt = guc_to_gt(guc);
|
|
struct intel_uncore *uncore = gt->uncore;
|
|
int ret;
|
|
|
|
guc_prepare_xfer(uncore);
|
|
|
|
/*
|
|
* Note that GuC needs the CSS header plus uKernel code to be copied
|
|
* by the DMA engine in one operation, whereas the RSA signature is
|
|
* loaded via MMIO.
|
|
*/
|
|
ret = guc_xfer_rsa(&guc->fw, uncore);
|
|
if (ret)
|
|
goto out;
|
|
|
|
/*
|
|
* Current uCode expects the code to be loaded at 8k; locations below
|
|
* this are used for the stack.
|
|
*/
|
|
ret = intel_uc_fw_upload(&guc->fw, 0x2000, UOS_MOVE);
|
|
if (ret)
|
|
goto out;
|
|
|
|
ret = guc_wait_ucode(uncore);
|
|
if (ret)
|
|
goto out;
|
|
|
|
intel_uc_fw_change_status(&guc->fw, INTEL_UC_FIRMWARE_RUNNING);
|
|
return 0;
|
|
|
|
out:
|
|
intel_uc_fw_change_status(&guc->fw, INTEL_UC_FIRMWARE_FAIL);
|
|
return ret;
|
|
}
|