2015-08-12 15:43:36 +01:00
/*
* 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 .
*
* 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 <linux/firmware.h>
# include "i915_drv.h"
# include "intel_guc.h"
/**
2015-10-19 16:10:54 -07:00
* DOC : GuC - specific firmware loader
2015-08-12 15:43:36 +01:00
*
* intel_guc :
* Top level structure of guc . It handles firmware loading and manages client
* pool and doorbells . intel_guc owns a i915_guc_client to replace the legacy
* ExecList submission .
*
* Firmware versioning :
* The firmware build process will generate a version header file with major and
* minor version defined . The versions are built into CSS header of firmware .
* i915 kernel driver set the minimal firmware version required per platform .
* The firmware installation package will install ( symbolic link ) proper version
* of firmware .
*
* GuC address space :
* GuC does not allow any gfx GGTT address that falls into range [ 0 , WOPCM_TOP ) ,
* which is reserved for Boot ROM , SRAM and WOPCM . Currently this top address is
* 512 K . In order to exclude 0 - 512 K address space from GGTT , all gfx objects
* used by GuC is pinned with PIN_OFFSET_BIAS along with size of WOPCM .
*
* Firmware log :
* Firmware log is enabled by setting i915 . guc_log_level to non - negative level .
* Log data is printed out via reading debugfs i915_guc_log_dump . Reading from
* i915_guc_load_status will print out firmware loading status and scratch
* registers value .
*
*/
2016-03-16 15:24:13 -07:00
# define I915_SKL_GUC_UCODE "i915 / skl_guc_ver6.bin"
2015-08-12 15:43:36 +01:00
MODULE_FIRMWARE ( I915_SKL_GUC_UCODE ) ;
/* User-friendly representation of an enum */
const char * intel_guc_fw_status_repr ( enum intel_guc_fw_status status )
{
switch ( status ) {
case GUC_FIRMWARE_FAIL :
return " FAIL " ;
case GUC_FIRMWARE_NONE :
return " NONE " ;
case GUC_FIRMWARE_PENDING :
return " PENDING " ;
case GUC_FIRMWARE_SUCCESS :
return " SUCCESS " ;
default :
return " UNKNOWN! " ;
}
} ;
2015-08-12 15:43:42 +01:00
static void direct_interrupts_to_host ( struct drm_i915_private * dev_priv )
{
2016-03-16 11:00:36 +00:00
struct intel_engine_cs * engine ;
2016-03-24 11:20:38 +00:00
int irqs ;
2015-08-12 15:43:42 +01:00
/* tell all command streamers NOT to forward interrupts and vblank to GuC */
irqs = _MASKED_FIELD ( GFX_FORWARD_VBLANK_MASK , GFX_FORWARD_VBLANK_NEVER ) ;
irqs | = _MASKED_BIT_DISABLE ( GFX_INTERRUPT_STEERING ) ;
2016-03-24 11:20:38 +00:00
for_each_engine ( engine , dev_priv )
2016-03-16 11:00:36 +00:00
I915_WRITE ( RING_MODE_GEN7 ( engine ) , irqs ) ;
2015-08-12 15:43:42 +01:00
/* route all GT interrupts to the host */
I915_WRITE ( GUC_BCS_RCS_IER , 0 ) ;
I915_WRITE ( GUC_VCS2_VCS1_IER , 0 ) ;
I915_WRITE ( GUC_WD_VECS_IER , 0 ) ;
}
static void direct_interrupts_to_guc ( struct drm_i915_private * dev_priv )
{
2016-03-16 11:00:36 +00:00
struct intel_engine_cs * engine ;
2016-03-24 11:20:38 +00:00
int irqs ;
2015-08-12 15:43:42 +01:00
/* tell all command streamers to forward interrupts and vblank to GuC */
irqs = _MASKED_FIELD ( GFX_FORWARD_VBLANK_MASK , GFX_FORWARD_VBLANK_ALWAYS ) ;
irqs | = _MASKED_BIT_ENABLE ( GFX_INTERRUPT_STEERING ) ;
2016-03-24 11:20:38 +00:00
for_each_engine ( engine , dev_priv )
2016-03-16 11:00:36 +00:00
I915_WRITE ( RING_MODE_GEN7 ( engine ) , irqs ) ;
2015-08-12 15:43:42 +01:00
/* route USER_INTERRUPT to Host, all others are sent to GuC. */
irqs = GT_RENDER_USER_INTERRUPT < < GEN8_RCS_IRQ_SHIFT |
GT_RENDER_USER_INTERRUPT < < GEN8_BCS_IRQ_SHIFT ;
/* These three registers have the same bit definitions */
I915_WRITE ( GUC_BCS_RCS_IER , ~ irqs ) ;
I915_WRITE ( GUC_VCS2_VCS1_IER , ~ irqs ) ;
I915_WRITE ( GUC_WD_VECS_IER , ~ irqs ) ;
}
2015-08-12 15:43:36 +01:00
static u32 get_gttype ( struct drm_i915_private * dev_priv )
{
/* XXX: GT type based on PCI device ID? field seems unused by fw */
return 0 ;
}
static u32 get_core_family ( struct drm_i915_private * dev_priv )
{
switch ( INTEL_INFO ( dev_priv ) - > gen ) {
case 9 :
return GFXCORE_FAMILY_GEN9 ;
default :
DRM_ERROR ( " GUC: unsupported core family \n " ) ;
return GFXCORE_FAMILY_UNKNOWN ;
}
}
static void set_guc_init_params ( struct drm_i915_private * dev_priv )
{
struct intel_guc * guc = & dev_priv - > guc ;
u32 params [ GUC_CTL_MAX_DWORDS ] ;
int i ;
memset ( & params , 0 , sizeof ( params ) ) ;
params [ GUC_CTL_DEVICE_INFO ] | =
( get_gttype ( dev_priv ) < < GUC_CTL_GTTYPE_SHIFT ) |
( get_core_family ( dev_priv ) < < GUC_CTL_COREFAMILY_SHIFT ) ;
/*
* GuC ARAT increment is 10 ns . GuC default scheduler quantum is one
* second . This ARAR is calculated by :
* Scheduler - Quantum - in - ns / ARAT - increment - in - ns = 1000000000 / 10
*/
params [ GUC_CTL_ARAT_HIGH ] = 0 ;
params [ GUC_CTL_ARAT_LOW ] = 100000000 ;
params [ GUC_CTL_WA ] | = GUC_CTL_WA_UK_BY_DRIVER ;
params [ GUC_CTL_FEATURE ] | = GUC_CTL_DISABLE_SCHEDULER |
GUC_CTL_VCS2_ENABLED ;
if ( i915 . guc_log_level > = 0 ) {
params [ GUC_CTL_LOG_PARAMS ] = guc - > log_flags ;
params [ GUC_CTL_DEBUG ] =
i915 . guc_log_level < < GUC_LOG_VERBOSITY_SHIFT ;
}
2015-12-18 12:00:12 -08:00
if ( guc - > ads_obj ) {
u32 ads = ( u32 ) i915_gem_obj_ggtt_offset ( guc - > ads_obj )
> > PAGE_SHIFT ;
params [ GUC_CTL_DEBUG ] | = ads < < GUC_ADS_ADDR_SHIFT ;
params [ GUC_CTL_DEBUG ] | = GUC_ADS_ENABLED ;
}
2015-08-12 15:43:39 +01:00
/* If GuC submission is enabled, set up additional parameters here */
if ( i915 . enable_guc_submission ) {
u32 pgs = i915_gem_obj_ggtt_offset ( dev_priv - > guc . ctx_pool_obj ) ;
u32 ctx_in_16 = GUC_MAX_GPU_CONTEXTS / 16 ;
pgs > > = PAGE_SHIFT ;
params [ GUC_CTL_CTXINFO ] = ( pgs < < GUC_CTL_BASE_ADDR_SHIFT ) |
( ctx_in_16 < < GUC_CTL_CTXNUM_IN16_SHIFT ) ;
params [ GUC_CTL_FEATURE ] | = GUC_CTL_KERNEL_SUBMISSIONS ;
/* Unmask this bit to enable the GuC's internal scheduler */
params [ GUC_CTL_FEATURE ] & = ~ GUC_CTL_DISABLE_SCHEDULER ;
}
2015-08-12 15:43:36 +01:00
I915_WRITE ( SOFT_SCRATCH ( 0 ) , 0 ) ;
for ( i = 0 ; i < GUC_CTL_MAX_DWORDS ; i + + )
I915_WRITE ( SOFT_SCRATCH ( 1 + i ) , params [ i ] ) ;
}
/*
* 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 .
*
2016-02-11 10:27:31 +00:00
* This is used for polling the GuC status in a wait_for ( )
2015-08-12 15:43:36 +01:00
* loop below .
*/
static inline bool guc_ucode_response ( struct drm_i915_private * dev_priv ,
u32 * status )
{
u32 val = I915_READ ( GUC_STATUS ) ;
2015-09-22 13:48:40 -07:00
u32 uk_val = val & GS_UKERNEL_MASK ;
2015-08-12 15:43:36 +01:00
* status = val ;
2015-09-22 13:48:40 -07:00
return ( uk_val = = GS_UKERNEL_READY | |
( ( val & GS_MIA_CORE_STATE ) & & uk_val = = GS_UKERNEL_LAPIC_DONE ) ) ;
2015-08-12 15:43:36 +01:00
}
/*
* Transfer the firmware image to RAM for execution by the microcontroller .
*
* Architecturally , the DMA engine is bidirectional , and can potentially even
* transfer between GTT locations . This functionality is left out of the API
* for now as there is no need for it .
*
* 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 .
*/
static int guc_ucode_xfer_dma ( struct drm_i915_private * dev_priv )
{
struct intel_guc_fw * guc_fw = & dev_priv - > guc . guc_fw ;
struct drm_i915_gem_object * fw_obj = guc_fw - > guc_fw_obj ;
unsigned long offset ;
struct sg_table * sg = fw_obj - > pages ;
2015-10-19 16:10:54 -07:00
u32 status , rsa [ UOS_RSA_SCRATCH_MAX_COUNT ] ;
2015-08-12 15:43:36 +01:00
int i , ret = 0 ;
2015-10-19 16:10:54 -07:00
/* where RSA signature starts */
offset = guc_fw - > rsa_offset ;
2015-08-12 15:43:36 +01:00
/* Copy RSA signature from the fw image to HW for verification */
2015-10-19 16:10:54 -07:00
sg_pcopy_to_buffer ( sg - > sgl , sg - > nents , rsa , sizeof ( rsa ) , offset ) ;
for ( i = 0 ; i < UOS_RSA_SCRATCH_MAX_COUNT ; i + + )
2015-09-18 20:03:24 +03:00
I915_WRITE ( UOS_RSA_SCRATCH ( i ) , rsa [ i ] ) ;
2015-08-12 15:43:36 +01:00
2015-10-19 16:10:54 -07:00
/* The header plus uCode will be copied to WOPCM via DMA, excluding any
* other components */
I915_WRITE ( DMA_COPY_SIZE , guc_fw - > header_size + guc_fw - > ucode_size ) ;
2015-08-12 15:43:36 +01:00
/* Set the source address for the new blob */
2015-10-19 16:10:54 -07:00
offset = i915_gem_obj_ggtt_offset ( fw_obj ) + guc_fw - > header_offset ;
2015-08-12 15:43:36 +01:00
I915_WRITE ( DMA_ADDR_0_LOW , lower_32_bits ( offset ) ) ;
I915_WRITE ( DMA_ADDR_0_HIGH , upper_32_bits ( offset ) & 0xFFFF ) ;
/*
* Set the DMA destination . Current uCode expects the code to be
* loaded at 8 k ; locations below this are used for the stack .
*/
I915_WRITE ( DMA_ADDR_1_LOW , 0x2000 ) ;
I915_WRITE ( DMA_ADDR_1_HIGH , DMA_ADDRESS_SPACE_WOPCM ) ;
/* Finally start the DMA */
I915_WRITE ( DMA_CTRL , _MASKED_BIT_ENABLE ( UOS_MOVE | START_DMA ) ) ;
/*
2016-02-11 10:27:31 +00:00
* Wait for the DMA to complete & the GuC to start up .
2015-08-12 15:43:36 +01:00
* NB : Docs recommend not using the interrupt for completion .
* Measurements indicate this should take no more than 20 ms , so a
* timeout here indicates that the GuC has failed and is unusable .
* ( Higher levels of the driver will attempt to fall back to
* execlist mode if this happens . )
*/
2016-02-11 10:27:31 +00:00
ret = wait_for ( guc_ucode_response ( dev_priv , & status ) , 100 ) ;
2015-08-12 15:43:36 +01:00
DRM_DEBUG_DRIVER ( " DMA status 0x%x, GuC status 0x%x \n " ,
I915_READ ( DMA_CTRL ) , status ) ;
if ( ( status & GS_BOOTROM_MASK ) = = GS_BOOTROM_RSA_FAILED ) {
DRM_ERROR ( " GuC firmware signature verification failed \n " ) ;
ret = - ENOEXEC ;
}
DRM_DEBUG_DRIVER ( " returning %d \n " , ret ) ;
return ret ;
}
/*
* Load the GuC firmware blob into the MinuteIA .
*/
static int guc_ucode_xfer ( struct drm_i915_private * dev_priv )
{
struct intel_guc_fw * guc_fw = & dev_priv - > guc . guc_fw ;
struct drm_device * dev = dev_priv - > dev ;
int ret ;
ret = i915_gem_object_set_to_gtt_domain ( guc_fw - > guc_fw_obj , false ) ;
if ( ret ) {
DRM_DEBUG_DRIVER ( " set-domain failed %d \n " , ret ) ;
return ret ;
}
ret = i915_gem_obj_ggtt_pin ( guc_fw - > guc_fw_obj , 0 , 0 ) ;
if ( ret ) {
DRM_DEBUG_DRIVER ( " pin failed %d \n " , ret ) ;
return ret ;
}
/* Invalidate GuC TLB to let GuC take the latest updates to GTT. */
I915_WRITE ( GEN8_GTCR , GEN8_GTCR_INVALIDATE ) ;
intel_uncore_forcewake_get ( dev_priv , FORCEWAKE_ALL ) ;
/* init WOPCM */
I915_WRITE ( GUC_WOPCM_SIZE , GUC_WOPCM_SIZE_VALUE ) ;
I915_WRITE ( DMA_GUC_WOPCM_OFFSET , GUC_WOPCM_OFFSET_VALUE ) ;
/* Enable MIA caching. GuC clock gating is disabled. */
I915_WRITE ( GUC_SHIM_CONTROL , GUC_SHIM_CONTROL_VALUE ) ;
2015-09-08 10:31:53 +01:00
/* WaDisableMinuteIaClockGating:skl,bxt */
2015-10-20 15:22:02 +03:00
if ( IS_SKL_REVID ( dev , 0 , SKL_REVID_B0 ) | |
2015-10-26 10:48:58 +00:00
IS_BXT_REVID ( dev , 0 , BXT_REVID_A1 ) ) {
2015-09-08 10:31:53 +01:00
I915_WRITE ( GUC_SHIM_CONTROL , ( I915_READ ( GUC_SHIM_CONTROL ) &
~ GUC_ENABLE_MIA_CLOCK_GATING ) ) ;
}
2015-08-12 15:43:36 +01:00
/* WaC6DisallowByGfxPause*/
I915_WRITE ( GEN6_GFXPAUSE , 0x30FFF ) ;
if ( IS_BROXTON ( dev ) )
I915_WRITE ( GEN9LP_GT_PM_CONFIG , GT_DOORBELL_ENABLE ) ;
else
I915_WRITE ( GEN9_GT_PM_CONFIG , GT_DOORBELL_ENABLE ) ;
if ( IS_GEN9 ( dev ) ) {
/* DOP Clock Gating Enable for GuC clocks */
I915_WRITE ( GEN7_MISCCPCTL , ( GEN8_DOP_CLOCK_GATE_GUC_ENABLE |
I915_READ ( GEN7_MISCCPCTL ) ) ) ;
/* allows for 5us before GT can go to RC6 */
I915_WRITE ( GUC_ARAT_C6DIS , 0x1FF ) ;
}
set_guc_init_params ( dev_priv ) ;
ret = guc_ucode_xfer_dma ( dev_priv ) ;
intel_uncore_forcewake_put ( dev_priv , FORCEWAKE_ALL ) ;
/*
* We keep the object pages for reuse during resume . But we can unpin it
* now that DMA has completed , so it doesn ' t continue to take up space .
*/
i915_gem_object_ggtt_unpin ( guc_fw - > guc_fw_obj ) ;
return ret ;
}
2016-04-04 18:50:56 +01:00
static int i915_reset_guc ( struct drm_i915_private * dev_priv )
{
int ret ;
u32 guc_status ;
ret = intel_guc_reset ( dev_priv ) ;
if ( ret ) {
DRM_ERROR ( " GuC reset failed, ret = %d \n " , ret ) ;
return ret ;
}
guc_status = I915_READ ( GUC_STATUS ) ;
WARN ( ! ( guc_status & GS_MIA_IN_RESET ) ,
" GuC status: 0x%x, MIA core expected to be in reset \n " , guc_status ) ;
return ret ;
}
2015-08-12 15:43:36 +01:00
/**
* intel_guc_ucode_load ( ) - load GuC uCode into the device
* @ dev : drm device
*
* Called from gem_init_hw ( ) during driver loading and also after a GPU reset .
*
* The firmware image should have already been fetched into memory by the
* earlier call to intel_guc_ucode_init ( ) , so here we need only check that
* is succeeded , and then transfer the image to the h / w .
*
* Return : non - zero code on error
*/
int intel_guc_ucode_load ( struct drm_device * dev )
{
struct drm_i915_private * dev_priv = dev - > dev_private ;
struct intel_guc_fw * guc_fw = & dev_priv - > guc . guc_fw ;
2016-04-04 18:50:57 +01:00
int retries , err = 0 ;
2015-08-12 15:43:36 +01:00
2015-10-23 11:10:59 +02:00
if ( ! i915 . enable_guc_submission )
return 0 ;
2015-08-12 15:43:36 +01:00
DRM_DEBUG_DRIVER ( " GuC fw status: fetch %s, load %s \n " ,
intel_guc_fw_status_repr ( guc_fw - > guc_fw_fetch_status ) ,
intel_guc_fw_status_repr ( guc_fw - > guc_fw_load_status ) ) ;
2015-08-12 15:43:42 +01:00
direct_interrupts_to_host ( dev_priv ) ;
2015-08-12 15:43:41 +01:00
2015-08-12 15:43:36 +01:00
if ( guc_fw - > guc_fw_fetch_status = = GUC_FIRMWARE_NONE )
return 0 ;
if ( guc_fw - > guc_fw_fetch_status = = GUC_FIRMWARE_SUCCESS & &
guc_fw - > guc_fw_load_status = = GUC_FIRMWARE_FAIL )
return - ENOEXEC ;
guc_fw - > guc_fw_load_status = GUC_FIRMWARE_PENDING ;
DRM_DEBUG_DRIVER ( " GuC fw fetch status %s \n " ,
intel_guc_fw_status_repr ( guc_fw - > guc_fw_fetch_status ) ) ;
switch ( guc_fw - > guc_fw_fetch_status ) {
case GUC_FIRMWARE_FAIL :
/* something went wrong :( */
err = - EIO ;
goto fail ;
case GUC_FIRMWARE_NONE :
case GUC_FIRMWARE_PENDING :
default :
/* "can't happen" */
WARN_ONCE ( 1 , " GuC fw %s invalid guc_fw_fetch_status %s [%d] \n " ,
guc_fw - > guc_fw_path ,
intel_guc_fw_status_repr ( guc_fw - > guc_fw_fetch_status ) ,
guc_fw - > guc_fw_fetch_status ) ;
err = - ENXIO ;
goto fail ;
case GUC_FIRMWARE_SUCCESS :
break ;
}
2015-08-12 15:43:39 +01:00
err = i915_guc_submission_init ( dev ) ;
if ( err )
goto fail ;
2016-04-04 18:50:56 +01:00
/*
* WaEnableuKernelHeaderValidFix : skl , bxt
* For BXT , this is only upto B0 but below WA is required for later
* steppings also so this is extended as well .
*/
/* WaEnableGuCBootHashCheckNotSet:skl,bxt */
2016-04-04 18:50:57 +01:00
for ( retries = 3 ; ; ) {
/*
* Always reset the GuC just before ( re ) loading , so
* that the state and timing are fairly predictable
*/
err = i915_reset_guc ( dev_priv ) ;
2016-04-04 18:50:56 +01:00
if ( err ) {
2016-04-04 18:50:57 +01:00
DRM_ERROR ( " GuC reset failed, err %d \n " , err ) ;
2016-04-04 18:50:56 +01:00
goto fail ;
}
2016-04-04 18:50:57 +01:00
err = guc_ucode_xfer ( dev_priv ) ;
if ( ! err )
break ;
if ( - - retries = = 0 )
goto fail ;
DRM_INFO ( " GuC fw load failed, err %d; will reset and "
" retry %d more time(s) \n " , err , retries ) ;
2016-04-04 18:50:56 +01:00
}
2015-08-12 15:43:36 +01:00
guc_fw - > guc_fw_load_status = GUC_FIRMWARE_SUCCESS ;
DRM_DEBUG_DRIVER ( " GuC fw status: fetch %s, load %s \n " ,
intel_guc_fw_status_repr ( guc_fw - > guc_fw_fetch_status ) ,
intel_guc_fw_status_repr ( guc_fw - > guc_fw_load_status ) ) ;
2015-08-12 15:43:41 +01:00
if ( i915 . enable_guc_submission ) {
2015-09-30 09:46:37 -07:00
/* The execbuf_client will be recreated. Release it first. */
i915_guc_submission_disable ( dev ) ;
2015-08-12 15:43:41 +01:00
err = i915_guc_submission_enable ( dev ) ;
if ( err )
goto fail ;
2015-08-12 15:43:42 +01:00
direct_interrupts_to_guc ( dev_priv ) ;
2015-08-12 15:43:41 +01:00
}
2015-08-12 15:43:36 +01:00
return 0 ;
fail :
2016-04-04 18:50:57 +01:00
DRM_ERROR ( " GuC firmware load failed, err %d \n " , err ) ;
2015-08-12 15:43:36 +01:00
if ( guc_fw - > guc_fw_load_status = = GUC_FIRMWARE_PENDING )
guc_fw - > guc_fw_load_status = GUC_FIRMWARE_FAIL ;
2015-08-12 15:43:42 +01:00
direct_interrupts_to_host ( dev_priv ) ;
2015-08-12 15:43:41 +01:00
i915_guc_submission_disable ( dev ) ;
2016-01-13 11:01:50 -08:00
i915_guc_submission_fini ( dev ) ;
2015-08-12 15:43:41 +01:00
2015-08-12 15:43:36 +01:00
return err ;
}
static void guc_fw_fetch ( struct drm_device * dev , struct intel_guc_fw * guc_fw )
{
struct drm_i915_gem_object * obj ;
const struct firmware * fw ;
2015-10-19 16:10:54 -07:00
struct guc_css_header * css ;
size_t size ;
2015-08-12 15:43:36 +01:00
int err ;
DRM_DEBUG_DRIVER ( " before requesting firmware: GuC fw fetch status %s \n " ,
intel_guc_fw_status_repr ( guc_fw - > guc_fw_fetch_status ) ) ;
err = request_firmware ( & fw , guc_fw - > guc_fw_path , & dev - > pdev - > dev ) ;
if ( err )
goto fail ;
if ( ! fw )
goto fail ;
DRM_DEBUG_DRIVER ( " fetch GuC fw from %s succeeded, fw %p \n " ,
guc_fw - > guc_fw_path , fw ) ;
2015-10-19 16:10:54 -07:00
/* Check the size of the blob before examining buffer contents */
if ( fw - > size < sizeof ( struct guc_css_header ) ) {
DRM_ERROR ( " Firmware header is missing \n " ) ;
2015-08-12 15:43:36 +01:00
goto fail ;
2015-10-19 16:10:54 -07:00
}
css = ( struct guc_css_header * ) fw - > data ;
/* Firmware bits always start from header */
guc_fw - > header_offset = 0 ;
guc_fw - > header_size = ( css - > header_size_dw - css - > modulus_size_dw -
css - > key_size_dw - css - > exponent_size_dw ) * sizeof ( u32 ) ;
if ( guc_fw - > header_size ! = sizeof ( struct guc_css_header ) ) {
DRM_ERROR ( " CSS header definition mismatch \n " ) ;
goto fail ;
}
/* then, uCode */
guc_fw - > ucode_offset = guc_fw - > header_offset + guc_fw - > header_size ;
guc_fw - > ucode_size = ( css - > size_dw - css - > header_size_dw ) * sizeof ( u32 ) ;
/* now RSA */
if ( css - > key_size_dw ! = UOS_RSA_SCRATCH_MAX_COUNT ) {
DRM_ERROR ( " RSA key size is bad \n " ) ;
goto fail ;
}
guc_fw - > rsa_offset = guc_fw - > ucode_offset + guc_fw - > ucode_size ;
guc_fw - > rsa_size = css - > key_size_dw * sizeof ( u32 ) ;
/* At least, it should have header, uCode and RSA. Size of all three. */
size = guc_fw - > header_size + guc_fw - > ucode_size + guc_fw - > rsa_size ;
if ( fw - > size < size ) {
DRM_ERROR ( " Missing firmware components \n " ) ;
goto fail ;
}
/* Header and uCode will be loaded to WOPCM. Size of the two. */
size = guc_fw - > header_size + guc_fw - > ucode_size ;
/* Top 32k of WOPCM is reserved (8K stack + 24k RC6 context). */
if ( size > GUC_WOPCM_SIZE_VALUE - 0x8000 ) {
DRM_ERROR ( " Firmware is too large to fit in WOPCM \n " ) ;
goto fail ;
}
2015-08-12 15:43:36 +01:00
/*
* The GuC firmware image has the version number embedded at a well - known
* offset within the firmware blob ; note that major / minor version are
* TWO bytes each ( i . e . u16 ) , although all pointers and offsets are defined
* in terms of bytes ( u8 ) .
*/
2015-10-19 16:10:54 -07:00
guc_fw - > guc_fw_major_found = css - > guc_sw_version > > 16 ;
guc_fw - > guc_fw_minor_found = css - > guc_sw_version & 0xFFFF ;
2015-08-12 15:43:36 +01:00
if ( guc_fw - > guc_fw_major_found ! = guc_fw - > guc_fw_major_wanted | |
guc_fw - > guc_fw_minor_found < guc_fw - > guc_fw_minor_wanted ) {
DRM_ERROR ( " GuC firmware version %d.%d, required %d.%d \n " ,
guc_fw - > guc_fw_major_found , guc_fw - > guc_fw_minor_found ,
guc_fw - > guc_fw_major_wanted , guc_fw - > guc_fw_minor_wanted ) ;
err = - ENOEXEC ;
goto fail ;
}
DRM_DEBUG_DRIVER ( " firmware version %d.%d OK (minimum %d.%d) \n " ,
guc_fw - > guc_fw_major_found , guc_fw - > guc_fw_minor_found ,
guc_fw - > guc_fw_major_wanted , guc_fw - > guc_fw_minor_wanted ) ;
2015-11-03 21:42:31 +00:00
mutex_lock ( & dev - > struct_mutex ) ;
2015-08-12 15:43:36 +01:00
obj = i915_gem_object_create_from_data ( dev , fw - > data , fw - > size ) ;
2015-11-03 21:42:31 +00:00
mutex_unlock ( & dev - > struct_mutex ) ;
2015-08-12 15:43:36 +01:00
if ( IS_ERR_OR_NULL ( obj ) ) {
err = obj ? PTR_ERR ( obj ) : - ENOMEM ;
goto fail ;
}
guc_fw - > guc_fw_obj = obj ;
guc_fw - > guc_fw_size = fw - > size ;
DRM_DEBUG_DRIVER ( " GuC fw fetch status SUCCESS, obj %p \n " ,
guc_fw - > guc_fw_obj ) ;
release_firmware ( fw ) ;
guc_fw - > guc_fw_fetch_status = GUC_FIRMWARE_SUCCESS ;
return ;
fail :
DRM_DEBUG_DRIVER ( " GuC fw fetch status FAIL; err %d, fw %p, obj %p \n " ,
err , fw , guc_fw - > guc_fw_obj ) ;
DRM_ERROR ( " Failed to fetch GuC firmware from %s (error %d) \n " ,
guc_fw - > guc_fw_path , err ) ;
2016-01-13 11:01:50 -08:00
mutex_lock ( & dev - > struct_mutex ) ;
2015-08-12 15:43:36 +01:00
obj = guc_fw - > guc_fw_obj ;
if ( obj )
drm_gem_object_unreference ( & obj - > base ) ;
guc_fw - > guc_fw_obj = NULL ;
2016-01-13 11:01:50 -08:00
mutex_unlock ( & dev - > struct_mutex ) ;
2015-08-12 15:43:36 +01:00
release_firmware ( fw ) ; /* OK even if fw is NULL */
guc_fw - > guc_fw_fetch_status = GUC_FIRMWARE_FAIL ;
}
/**
* intel_guc_ucode_init ( ) - define parameters and fetch firmware
* @ dev : drm device
*
* Called early during driver load , but after GEM is initialised .
*
* The firmware will be transferred to the GuC ' s memory later ,
* when intel_guc_ucode_load ( ) is called .
*/
void intel_guc_ucode_init ( struct drm_device * dev )
{
struct drm_i915_private * dev_priv = dev - > dev_private ;
struct intel_guc_fw * guc_fw = & dev_priv - > guc . guc_fw ;
const char * fw_path ;
if ( ! HAS_GUC_SCHED ( dev ) )
i915 . enable_guc_submission = false ;
if ( ! HAS_GUC_UCODE ( dev ) ) {
fw_path = NULL ;
} else if ( IS_SKYLAKE ( dev ) ) {
fw_path = I915_SKL_GUC_UCODE ;
2016-03-16 15:24:13 -07:00
guc_fw - > guc_fw_major_wanted = 6 ;
guc_fw - > guc_fw_minor_wanted = 1 ;
2015-08-12 15:43:36 +01:00
} else {
i915 . enable_guc_submission = false ;
fw_path = " " ; /* unknown device */
}
2015-10-23 11:10:59 +02:00
if ( ! i915 . enable_guc_submission )
return ;
2015-08-12 15:43:36 +01:00
guc_fw - > guc_dev = dev ;
guc_fw - > guc_fw_path = fw_path ;
guc_fw - > guc_fw_fetch_status = GUC_FIRMWARE_NONE ;
guc_fw - > guc_fw_load_status = GUC_FIRMWARE_NONE ;
if ( fw_path = = NULL )
return ;
if ( * fw_path = = ' \0 ' ) {
DRM_ERROR ( " No GuC firmware known for this platform \n " ) ;
guc_fw - > guc_fw_fetch_status = GUC_FIRMWARE_FAIL ;
return ;
}
guc_fw - > guc_fw_fetch_status = GUC_FIRMWARE_PENDING ;
DRM_DEBUG_DRIVER ( " GuC firmware pending, path %s \n " , fw_path ) ;
guc_fw_fetch ( dev , guc_fw ) ;
/* status must now be FAIL or SUCCESS */
}
/**
* intel_guc_ucode_fini ( ) - clean up all allocated resources
* @ dev : drm device
*/
void intel_guc_ucode_fini ( struct drm_device * dev )
{
struct drm_i915_private * dev_priv = dev - > dev_private ;
struct intel_guc_fw * guc_fw = & dev_priv - > guc . guc_fw ;
2016-01-13 11:01:50 -08:00
mutex_lock ( & dev - > struct_mutex ) ;
2015-08-12 15:43:42 +01:00
direct_interrupts_to_host ( dev_priv ) ;
2016-01-13 11:01:50 -08:00
i915_guc_submission_disable ( dev ) ;
2015-08-12 15:43:39 +01:00
i915_guc_submission_fini ( dev ) ;
2015-08-12 15:43:36 +01:00
if ( guc_fw - > guc_fw_obj )
drm_gem_object_unreference ( & guc_fw - > guc_fw_obj - > base ) ;
guc_fw - > guc_fw_obj = NULL ;
2015-11-03 21:42:31 +00:00
mutex_unlock ( & dev - > struct_mutex ) ;
2015-08-12 15:43:36 +01:00
guc_fw - > guc_fw_fetch_status = GUC_FIRMWARE_NONE ;
}