Commit 33a732f4 authored by Alex Dai's avatar Alex Dai Committed by Daniel Vetter

drm/i915: GuC-specific firmware loader

This fetches the required firmware image from the filesystem,
then loads it into the GuC's memory via a dedicated DMA engine.

This patch is derived from GuC loading work originally done by
Vinit Azad and Ben Widawsky.

v2:
    Various improvements per review comments by Chris Wilson

v3:
    Removed 'wait' parameter to intel_guc_ucode_load() as firmware
        prefetch is no longer supported in the common firmware loader,
	per Daniel Vetter's request.
    Firmware checker callback fn now returns errno rather than bool.

v4:
    Squash uC-independent code into GuC-specifc loader [Daniel Vetter]
    Don't keep the driver working (by falling back to execlist mode)
        if GuC firmware loading fails [Daniel Vetter]

v5:
    Clarify WOPCM-related #defines [Tom O'Rourke]
    Delete obsolete code no longer required with current h/w & f/w
        [Tom O'Rourke]
    Move the call to intel_guc_ucode_init() later, so that it can
        allocate GEM objects, and have it fetch the firmware; then
	intel_guc_ucode_load() doesn't need to fetch it later.
        [Daniel Vetter].

v6:
    Update comment describing intel_guc_ucode_load() [Tom O'Rourke]

Issue: VIZ-4884
Signed-off-by: default avatarAlex Dai <yu.dai@intel.com>
Signed-off-by: default avatarDave Gordon <david.s.gordon@intel.com>
Reviewed-by: default avatarTom O'Rourke <Tom.O'Rourke@intel.com>
Signed-off-by: default avatarDaniel Vetter <daniel.vetter@ffwll.ch>
parent 04a60f9f
...@@ -40,6 +40,9 @@ i915-y += i915_cmd_parser.o \ ...@@ -40,6 +40,9 @@ i915-y += i915_cmd_parser.o \
intel_ringbuffer.o \ intel_ringbuffer.o \
intel_uncore.o intel_uncore.o
# general-purpose microcontroller (GuC) support
i915-y += intel_guc_loader.o
# autogenerated null render state # autogenerated null render state
i915-y += intel_renderstate_gen6.o \ i915-y += intel_renderstate_gen6.o \
intel_renderstate_gen7.o \ intel_renderstate_gen7.o \
......
...@@ -435,6 +435,11 @@ static int i915_load_modeset_init(struct drm_device *dev) ...@@ -435,6 +435,11 @@ static int i915_load_modeset_init(struct drm_device *dev)
* working irqs for e.g. gmbus and dp aux transfers. */ * working irqs for e.g. gmbus and dp aux transfers. */
intel_modeset_init(dev); intel_modeset_init(dev);
/* intel_guc_ucode_init() needs the mutex to allocate GEM objects */
mutex_lock(&dev->struct_mutex);
intel_guc_ucode_init(dev);
mutex_unlock(&dev->struct_mutex);
ret = i915_gem_init(dev); ret = i915_gem_init(dev);
if (ret) if (ret)
goto cleanup_irq; goto cleanup_irq;
...@@ -476,6 +481,9 @@ static int i915_load_modeset_init(struct drm_device *dev) ...@@ -476,6 +481,9 @@ static int i915_load_modeset_init(struct drm_device *dev)
i915_gem_context_fini(dev); i915_gem_context_fini(dev);
mutex_unlock(&dev->struct_mutex); mutex_unlock(&dev->struct_mutex);
cleanup_irq: cleanup_irq:
mutex_lock(&dev->struct_mutex);
intel_guc_ucode_fini(dev);
mutex_unlock(&dev->struct_mutex);
drm_irq_uninstall(dev); drm_irq_uninstall(dev);
cleanup_gem_stolen: cleanup_gem_stolen:
i915_gem_cleanup_stolen(dev); i915_gem_cleanup_stolen(dev);
...@@ -1128,6 +1136,7 @@ int i915_driver_unload(struct drm_device *dev) ...@@ -1128,6 +1136,7 @@ int i915_driver_unload(struct drm_device *dev)
flush_workqueue(dev_priv->wq); flush_workqueue(dev_priv->wq);
mutex_lock(&dev->struct_mutex); mutex_lock(&dev->struct_mutex);
intel_guc_ucode_fini(dev);
i915_gem_cleanup_ringbuffer(dev); i915_gem_cleanup_ringbuffer(dev);
i915_gem_context_fini(dev); i915_gem_context_fini(dev);
mutex_unlock(&dev->struct_mutex); mutex_unlock(&dev->struct_mutex);
......
...@@ -50,6 +50,7 @@ ...@@ -50,6 +50,7 @@
#include <linux/intel-iommu.h> #include <linux/intel-iommu.h>
#include <linux/kref.h> #include <linux/kref.h>
#include <linux/pm_qos.h> #include <linux/pm_qos.h>
#include "intel_guc.h"
/* General customization: /* General customization:
*/ */
...@@ -1709,6 +1710,8 @@ struct drm_i915_private { ...@@ -1709,6 +1710,8 @@ struct drm_i915_private {
struct i915_virtual_gpu vgpu; struct i915_virtual_gpu vgpu;
struct intel_guc guc;
struct intel_csr csr; struct intel_csr csr;
/* Display CSR-related protection */ /* Display CSR-related protection */
...@@ -1953,6 +1956,11 @@ static inline struct drm_i915_private *dev_to_i915(struct device *dev) ...@@ -1953,6 +1956,11 @@ static inline struct drm_i915_private *dev_to_i915(struct device *dev)
return to_i915(dev_get_drvdata(dev)); return to_i915(dev_get_drvdata(dev));
} }
static inline struct drm_i915_private *guc_to_i915(struct intel_guc *guc)
{
return container_of(guc, struct drm_i915_private, guc);
}
/* Iterate over initialised rings */ /* Iterate over initialised rings */
#define for_each_ring(ring__, dev_priv__, i__) \ #define for_each_ring(ring__, dev_priv__, i__) \
for ((i__) = 0; (i__) < I915_NUM_RINGS; (i__)++) \ for ((i__) = 0; (i__) < I915_NUM_RINGS; (i__)++) \
...@@ -2557,6 +2565,9 @@ struct drm_i915_cmd_table { ...@@ -2557,6 +2565,9 @@ struct drm_i915_cmd_table {
#define HAS_CSR(dev) (IS_SKYLAKE(dev)) #define HAS_CSR(dev) (IS_SKYLAKE(dev))
#define HAS_GUC_UCODE(dev) (IS_GEN9(dev))
#define HAS_GUC_SCHED(dev) (IS_GEN9(dev))
#define HAS_RESOURCE_STREAMER(dev) (IS_HASWELL(dev) || \ #define HAS_RESOURCE_STREAMER(dev) (IS_HASWELL(dev) || \
INTEL_INFO(dev)->gen >= 8) INTEL_INFO(dev)->gen >= 8)
......
...@@ -4681,6 +4681,22 @@ i915_gem_init_hw(struct drm_device *dev) ...@@ -4681,6 +4681,22 @@ i915_gem_init_hw(struct drm_device *dev)
goto out; goto out;
} }
/* We can't enable contexts until all firmware is loaded */
ret = intel_guc_ucode_load(dev);
if (ret) {
/*
* If we got an error and GuC submission is enabled, map
* the error to -EIO so the GPU will be declared wedged.
* OTOH, if we didn't intend to use the GuC anyway, just
* discard the error and carry on.
*/
DRM_ERROR("Failed to initialize GuC, error %d%s\n", ret,
i915.enable_guc_submission ? "" : " (ignored)");
ret = i915.enable_guc_submission ? -EIO : 0;
if (ret)
goto out;
}
/* Now it is safe to go back round and do everything else: */ /* Now it is safe to go back round and do everything else: */
for_each_ring(ring, dev_priv, i) { for_each_ring(ring, dev_priv, i) {
struct drm_i915_gem_request *req; struct drm_i915_gem_request *req;
......
...@@ -38,10 +38,6 @@ ...@@ -38,10 +38,6 @@
#define GS_MIA_SHIFT 16 #define GS_MIA_SHIFT 16
#define GS_MIA_MASK (0x07 << GS_MIA_SHIFT) #define GS_MIA_MASK (0x07 << GS_MIA_SHIFT)
#define GUC_WOPCM_SIZE 0xc050
#define GUC_WOPCM_SIZE_VALUE (0x80 << 12) /* 512KB */
#define GUC_WOPCM_OFFSET 0x80000 /* 512KB */
#define SOFT_SCRATCH(n) (0xc180 + ((n) * 4)) #define SOFT_SCRATCH(n) (0xc180 + ((n) * 4))
#define UOS_RSA_SCRATCH_0 0xc200 #define UOS_RSA_SCRATCH_0 0xc200
...@@ -56,10 +52,18 @@ ...@@ -56,10 +52,18 @@
#define UOS_MOVE (1<<4) #define UOS_MOVE (1<<4)
#define START_DMA (1<<0) #define START_DMA (1<<0)
#define DMA_GUC_WOPCM_OFFSET 0xc340 #define DMA_GUC_WOPCM_OFFSET 0xc340
#define GUC_WOPCM_OFFSET_VALUE 0x80000 /* 512KB */
#define GUC_WOPCM_SIZE 0xc050
#define GUC_WOPCM_SIZE_VALUE (0x80 << 12) /* 512KB */
/* GuC addresses below GUC_WOPCM_TOP don't map through the GTT */
#define GUC_WOPCM_TOP (GUC_WOPCM_SIZE_VALUE)
#define GEN8_GT_PM_CONFIG 0x138140 #define GEN8_GT_PM_CONFIG 0x138140
#define GEN9LP_GT_PM_CONFIG 0x138140
#define GEN9_GT_PM_CONFIG 0x13816c #define GEN9_GT_PM_CONFIG 0x13816c
#define GEN8_GT_DOORBELL_ENABLE (1<<0) #define GT_DOORBELL_ENABLE (1<<0)
#define GEN8_GTCR 0x4274 #define GEN8_GTCR 0x4274
#define GEN8_GTCR_INVALIDATE (1<<0) #define GEN8_GTCR_INVALIDATE (1<<0)
...@@ -80,7 +84,8 @@ ...@@ -80,7 +84,8 @@
GUC_ENABLE_READ_CACHE_LOGIC | \ GUC_ENABLE_READ_CACHE_LOGIC | \
GUC_ENABLE_MIA_CACHING | \ GUC_ENABLE_MIA_CACHING | \
GUC_ENABLE_READ_CACHE_FOR_SRAM_DATA | \ GUC_ENABLE_READ_CACHE_FOR_SRAM_DATA | \
GUC_ENABLE_READ_CACHE_FOR_WOPCM_DATA) GUC_ENABLE_READ_CACHE_FOR_WOPCM_DATA | \
GUC_ENABLE_MIA_CLOCK_GATING)
#define HOST2GUC_INTERRUPT 0xc4c8 #define HOST2GUC_INTERRUPT 0xc4c8
#define HOST2GUC_TRIGGER (1<<0) #define HOST2GUC_TRIGGER (1<<0)
......
...@@ -6861,6 +6861,8 @@ enum skl_disp_power_wells { ...@@ -6861,6 +6861,8 @@ enum skl_disp_power_wells {
#define GEN7_MISCCPCTL (0x9424) #define GEN7_MISCCPCTL (0x9424)
#define GEN7_DOP_CLOCK_GATE_ENABLE (1<<0) #define GEN7_DOP_CLOCK_GATE_ENABLE (1<<0)
#define GEN8_DOP_CLOCK_GATE_CFCLK_ENABLE (1<<2)
#define GEN8_DOP_CLOCK_GATE_GUC_ENABLE (1<<4)
#define GEN8_GARBCNTL 0xB004 #define GEN8_GARBCNTL 0xB004
#define GEN9_GAPS_TSV_CREDIT_DISABLE (1<<7) #define GEN9_GAPS_TSV_CREDIT_DISABLE (1<<7)
......
/*
* Copyright © 2014 Intel Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*
*/
#ifndef _INTEL_GUC_H_
#define _INTEL_GUC_H_
#include "intel_guc_fwif.h"
#include "i915_guc_reg.h"
enum intel_guc_fw_status {
GUC_FIRMWARE_FAIL = -1,
GUC_FIRMWARE_NONE = 0,
GUC_FIRMWARE_PENDING,
GUC_FIRMWARE_SUCCESS
};
/*
* This structure encapsulates all the data needed during the process
* of fetching, caching, and loading the firmware image into the GuC.
*/
struct intel_guc_fw {
struct drm_device * guc_dev;
const char * guc_fw_path;
size_t guc_fw_size;
struct drm_i915_gem_object * guc_fw_obj;
enum intel_guc_fw_status guc_fw_fetch_status;
enum intel_guc_fw_status guc_fw_load_status;
uint16_t guc_fw_major_wanted;
uint16_t guc_fw_minor_wanted;
uint16_t guc_fw_major_found;
uint16_t guc_fw_minor_found;
};
struct intel_guc {
struct intel_guc_fw guc_fw;
uint32_t log_flags;
};
/* intel_guc_loader.c */
extern void intel_guc_ucode_init(struct drm_device *dev);
extern int intel_guc_ucode_load(struct drm_device *dev);
extern void intel_guc_ucode_fini(struct drm_device *dev);
extern const char *intel_guc_fw_status_repr(enum intel_guc_fw_status status);
#endif
...@@ -32,9 +32,8 @@ ...@@ -32,9 +32,8 @@
* EDITING THIS FILE IS THEREFORE NOT RECOMMENDED - YOUR CHANGES MAY BE LOST. * EDITING THIS FILE IS THEREFORE NOT RECOMMENDED - YOUR CHANGES MAY BE LOST.
*/ */
#define GFXCORE_FAMILY_GEN8 11
#define GFXCORE_FAMILY_GEN9 12 #define GFXCORE_FAMILY_GEN9 12
#define GFXCORE_FAMILY_FORCE_ULONG 0x7fffffff #define GFXCORE_FAMILY_UNKNOWN 0x7fffffff
#define GUC_CTX_PRIORITY_CRITICAL 0 #define GUC_CTX_PRIORITY_CRITICAL 0
#define GUC_CTX_PRIORITY_HIGH 1 #define GUC_CTX_PRIORITY_HIGH 1
......
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment