2017-10-04 15:33:25 +00:00
/*
* Copyright © 2016 - 2017 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 .
*
*/
2019-05-27 18:35:59 +00:00
# include <linux/bitfield.h>
2017-10-04 15:33:25 +00:00
# include <linux/firmware.h>
2017-10-17 09:44:49 +00:00
# include <drm/drm_print.h>
2017-10-04 15:33:25 +00:00
# include "intel_uc_fw.h"
2019-07-25 14:13:08 +00:00
# include "intel_uc_fw_abi.h"
2017-10-04 15:33:25 +00:00
# include "i915_drv.h"
2019-07-24 17:18:08 -07:00
/*
* List of required GuC and HuC binaries per - platform .
* Must be ordered based on platform + revid , from newer to older .
*/
# define INTEL_UC_FIRMWARE_DEFS(fw_def, guc_def, huc_def) \
fw_def ( ICELAKE , 0 , guc_def ( icl , 33 , 0 , 0 ) , huc_def ( icl , 8 , 4 , 3238 ) ) \
fw_def ( COFFEELAKE , 0 , guc_def ( kbl , 33 , 0 , 0 ) , huc_def ( kbl , 02 , 00 , 1810 ) ) \
fw_def ( GEMINILAKE , 0 , guc_def ( glk , 33 , 0 , 0 ) , huc_def ( glk , 03 , 01 , 2893 ) ) \
fw_def ( KABYLAKE , 0 , guc_def ( kbl , 33 , 0 , 0 ) , huc_def ( kbl , 02 , 00 , 1810 ) ) \
fw_def ( BROXTON , 0 , guc_def ( bxt , 33 , 0 , 0 ) , huc_def ( bxt , 01 , 8 , 2893 ) ) \
fw_def ( SKYLAKE , 0 , guc_def ( skl , 33 , 0 , 0 ) , huc_def ( skl , 01 , 07 , 1398 ) )
# define __MAKE_UC_FW_PATH(prefix_, name_, separator_, major_, minor_, patch_) \
" i915/ " \
__stringify ( prefix_ ) name_ \
__stringify ( major_ ) separator_ \
__stringify ( minor_ ) separator_ \
__stringify ( patch_ ) " .bin "
# define MAKE_GUC_FW_PATH(prefix_, major_, minor_, patch_) \
__MAKE_UC_FW_PATH ( prefix_ , " _guc_ " , " . " , major_ , minor_ , patch_ )
# define MAKE_HUC_FW_PATH(prefix_, major_, minor_, bld_num_) \
__MAKE_UC_FW_PATH ( prefix_ , " _huc_ver " , " _ " , major_ , minor_ , bld_num_ )
/* All blobs need to be declared via MODULE_FIRMWARE() */
# define INTEL_UC_MODULE_FW(platform_, revid_, guc_, huc_) \
MODULE_FIRMWARE ( guc_ ) ; \
MODULE_FIRMWARE ( huc_ ) ;
INTEL_UC_FIRMWARE_DEFS ( INTEL_UC_MODULE_FW , MAKE_GUC_FW_PATH , MAKE_HUC_FW_PATH )
/* The below structs and macros are used to iterate across the list of blobs */
struct __packed uc_fw_blob {
u8 major ;
u8 minor ;
const char * path ;
} ;
# define UC_FW_BLOB(major_, minor_, path_) \
{ . major = major_ , . minor = minor_ , . path = path_ }
# define GUC_FW_BLOB(prefix_, major_, minor_, patch_) \
UC_FW_BLOB ( major_ , minor_ , \
MAKE_GUC_FW_PATH ( prefix_ , major_ , minor_ , patch_ ) )
# define HUC_FW_BLOB(prefix_, major_, minor_, bld_num_) \
UC_FW_BLOB ( major_ , minor_ , \
MAKE_HUC_FW_PATH ( prefix_ , major_ , minor_ , bld_num_ ) )
struct __packed uc_fw_platform_requirement {
enum intel_platform p ;
u8 rev ; /* first platform rev using this FW */
const struct uc_fw_blob blobs [ INTEL_UC_FW_NUM_TYPES ] ;
} ;
# define MAKE_FW_LIST(platform_, revid_, guc_, huc_) \
{ \
. p = INTEL_ # # platform_ , \
. rev = revid_ , \
. blobs [ INTEL_UC_FW_TYPE_GUC ] = guc_ , \
. blobs [ INTEL_UC_FW_TYPE_HUC ] = huc_ , \
} ,
static void
__uc_fw_auto_select ( struct intel_uc_fw * uc_fw , enum intel_platform p , u8 rev )
{
static const struct uc_fw_platform_requirement fw_blobs [ ] = {
INTEL_UC_FIRMWARE_DEFS ( MAKE_FW_LIST , GUC_FW_BLOB , HUC_FW_BLOB )
} ;
int i ;
for ( i = 0 ; i < ARRAY_SIZE ( fw_blobs ) & & p < = fw_blobs [ i ] . p ; i + + ) {
if ( p = = fw_blobs [ i ] . p & & rev > = fw_blobs [ i ] . rev ) {
const struct uc_fw_blob * blob =
& fw_blobs [ i ] . blobs [ uc_fw - > type ] ;
uc_fw - > path = blob - > path ;
uc_fw - > major_ver_wanted = blob - > major ;
uc_fw - > minor_ver_wanted = blob - > minor ;
break ;
}
}
/* make sure the list is ordered as expected */
if ( IS_ENABLED ( CONFIG_DRM_I915_SELFTEST ) ) {
for ( i = 1 ; i < ARRAY_SIZE ( fw_blobs ) ; i + + ) {
if ( fw_blobs [ i ] . p < fw_blobs [ i - 1 ] . p )
continue ;
if ( fw_blobs [ i ] . p = = fw_blobs [ i - 1 ] . p & &
fw_blobs [ i ] . rev < fw_blobs [ i - 1 ] . rev )
continue ;
pr_err ( " invalid FW blob order: %s r%u comes before %s r%u \n " ,
intel_platform_name ( fw_blobs [ i - 1 ] . p ) ,
fw_blobs [ i - 1 ] . rev ,
intel_platform_name ( fw_blobs [ i ] . p ) ,
fw_blobs [ i ] . rev ) ;
uc_fw - > path = NULL ;
}
}
2019-07-31 22:33:19 +00:00
/* We don't want to enable GuC/HuC on pre-Gen11 by default */
if ( i915_modparams . enable_guc = = - 1 & & p < INTEL_ICELAKE )
uc_fw - > path = NULL ;
}
static const char * __override_guc_firmware_path ( void )
{
if ( i915_modparams . enable_guc & ( ENABLE_GUC_SUBMISSION |
ENABLE_GUC_LOAD_HUC ) )
return i915_modparams . guc_firmware_path ;
return " " ;
}
static const char * __override_huc_firmware_path ( void )
{
if ( i915_modparams . enable_guc & ENABLE_GUC_LOAD_HUC )
return i915_modparams . huc_firmware_path ;
return " " ;
2019-07-24 17:18:08 -07:00
}
2019-08-07 18:37:59 +00:00
static void __uc_fw_user_override ( struct intel_uc_fw * uc_fw )
2019-07-24 17:18:08 -07:00
{
2019-08-07 18:37:59 +00:00
const char * path = NULL ;
2019-07-24 17:18:08 -07:00
switch ( uc_fw - > type ) {
case INTEL_UC_FW_TYPE_GUC :
2019-08-07 18:37:59 +00:00
path = __override_guc_firmware_path ( ) ;
2019-07-24 17:18:08 -07:00
break ;
case INTEL_UC_FW_TYPE_HUC :
2019-08-07 18:37:59 +00:00
path = __override_huc_firmware_path ( ) ;
2019-07-24 17:18:08 -07:00
break ;
}
2019-08-07 18:37:59 +00:00
if ( unlikely ( path ) ) {
uc_fw - > path = path ;
uc_fw - > user_overridden = true ;
}
2019-07-24 17:18:08 -07:00
}
/**
* intel_uc_fw_init_early - initialize the uC object and select the firmware
* @ uc_fw : uC firmware
* @ type : type of uC
2019-08-07 17:00:29 +00:00
* @ supported : is uC support possible
* @ platform : platform identifier
* @ rev : hardware revision
2019-07-24 17:18:08 -07:00
*
* Initialize the state of our uC object and relevant tracking and select the
* firmware to fetch and load .
*/
void intel_uc_fw_init_early ( struct intel_uc_fw * uc_fw ,
2019-08-07 17:00:29 +00:00
enum intel_uc_fw_type type , bool supported ,
enum intel_platform platform , u8 rev )
2019-07-24 17:18:08 -07:00
{
/*
2019-07-24 17:18:09 -07:00
* we use FIRMWARE_UNINITIALIZED to detect checks against uc_fw - > status
2019-07-24 17:18:08 -07:00
* before we ' re looked at the HW caps to see if we have uc support
*/
BUILD_BUG_ON ( INTEL_UC_FIRMWARE_UNINITIALIZED ) ;
2019-07-24 17:18:09 -07:00
GEM_BUG_ON ( uc_fw - > status ) ;
2019-07-24 17:18:08 -07:00
GEM_BUG_ON ( uc_fw - > path ) ;
uc_fw - > type = type ;
2019-08-07 18:37:59 +00:00
if ( supported ) {
2019-08-07 17:00:29 +00:00
__uc_fw_auto_select ( uc_fw , platform , rev ) ;
2019-08-07 18:37:59 +00:00
__uc_fw_user_override ( uc_fw ) ;
}
2019-07-24 17:18:08 -07:00
2019-07-29 11:26:12 +00:00
if ( uc_fw - > path & & * uc_fw - > path )
2019-07-24 17:18:09 -07:00
uc_fw - > status = INTEL_UC_FIRMWARE_SELECTED ;
else
uc_fw - > status = INTEL_UC_FIRMWARE_NOT_SUPPORTED ;
2019-07-24 17:18:08 -07:00
}
2019-08-07 18:37:59 +00:00
static void __force_fw_fetch_failures ( struct intel_uc_fw * uc_fw ,
struct drm_i915_private * i915 ,
int e )
{
bool user = e = = - EINVAL ;
if ( i915_inject_load_error ( i915 , e ) ) {
/* non-existing blob */
uc_fw - > path = " <invalid> " ;
uc_fw - > user_overridden = user ;
} else if ( i915_inject_load_error ( i915 , e ) ) {
/* require next major version */
uc_fw - > major_ver_wanted + = 1 ;
uc_fw - > minor_ver_wanted = 0 ;
uc_fw - > user_overridden = user ;
} else if ( i915_inject_load_error ( i915 , e ) ) {
/* require next minor version */
uc_fw - > minor_ver_wanted + = 1 ;
uc_fw - > user_overridden = user ;
} else if ( uc_fw - > major_ver_wanted & & i915_inject_load_error ( i915 , e ) ) {
/* require prev major version */
uc_fw - > major_ver_wanted - = 1 ;
uc_fw - > minor_ver_wanted = 0 ;
uc_fw - > user_overridden = user ;
} else if ( uc_fw - > minor_ver_wanted & & i915_inject_load_error ( i915 , e ) ) {
/* require prev minor version - hey, this should work! */
uc_fw - > minor_ver_wanted - = 1 ;
uc_fw - > user_overridden = user ;
} else if ( user & & i915_inject_load_error ( i915 , e ) ) {
/* officially unsupported platform */
uc_fw - > major_ver_wanted = 0 ;
uc_fw - > minor_ver_wanted = 0 ;
uc_fw - > user_overridden = true ;
}
}
2017-10-04 15:33:25 +00:00
/**
* intel_uc_fw_fetch - fetch uC firmware
* @ uc_fw : uC firmware
2019-07-27 10:54:41 +01:00
* @ i915 : device private
2017-10-04 15:33:25 +00:00
*
* Fetch uC firmware into GEM obj .
2019-08-07 17:00:30 +00:00
*
* Return : 0 on success , a negative errno code on failure .
2017-10-04 15:33:25 +00:00
*/
2019-08-07 17:00:30 +00:00
int intel_uc_fw_fetch ( struct intel_uc_fw * uc_fw , struct drm_i915_private * i915 )
2017-10-04 15:33:25 +00:00
{
2019-08-07 18:37:59 +00:00
struct device * dev = i915 - > drm . dev ;
2017-10-04 15:33:25 +00:00
struct drm_i915_gem_object * obj ;
const struct firmware * fw = NULL ;
struct uc_css_header * css ;
size_t size ;
int err ;
2019-07-13 11:00:08 +01:00
GEM_BUG_ON ( ! intel_uc_fw_supported ( uc_fw ) ) ;
2019-08-07 18:37:59 +00:00
err = i915_inject_load_error ( i915 , - ENXIO ) ;
2019-07-24 17:18:09 -07:00
if ( err )
2019-08-07 18:37:59 +00:00
return err ;
2017-10-04 15:33:25 +00:00
2019-08-07 18:37:59 +00:00
__force_fw_fetch_failures ( uc_fw , i915 , - EINVAL ) ;
__force_fw_fetch_failures ( uc_fw , i915 , - ESTALE ) ;
err = request_firmware ( & fw , uc_fw - > path , dev ) ;
if ( err )
goto fail ;
2017-10-04 15:33:25 +00:00
/* Check the size of the blob before examining buffer contents */
2019-08-07 18:37:59 +00:00
if ( unlikely ( fw - > size < sizeof ( struct uc_css_header ) ) ) {
dev_warn ( dev , " %s firmware %s: invalid size: %zu < %zu \n " ,
intel_uc_fw_type_repr ( uc_fw - > type ) , uc_fw - > path ,
2017-10-16 14:47:18 +00:00
fw - > size , sizeof ( struct uc_css_header ) ) ;
err = - ENODATA ;
2017-10-04 15:33:25 +00:00
goto fail ;
}
css = ( struct uc_css_header * ) fw - > data ;
2019-07-26 18:42:10 +00:00
/* Check integrity of size values inside CSS header */
size = ( css - > header_size_dw - css - > key_size_dw - css - > modulus_size_dw -
css - > exponent_size_dw ) * sizeof ( u32 ) ;
2019-08-07 18:37:59 +00:00
if ( unlikely ( size ! = sizeof ( struct uc_css_header ) ) ) {
dev_warn ( dev ,
" %s firmware %s: unexpected header size: %zu != %zu \n " ,
intel_uc_fw_type_repr ( uc_fw - > type ) , uc_fw - > path ,
fw - > size , sizeof ( struct uc_css_header ) ) ;
err = - EPROTO ;
2017-10-04 15:33:25 +00:00
goto fail ;
}
2019-07-26 18:42:10 +00:00
/* uCode size must calculated from other sizes */
2017-10-04 15:33:25 +00:00
uc_fw - > ucode_size = ( css - > size_dw - css - > header_size_dw ) * sizeof ( u32 ) ;
/* now RSA */
2019-08-07 18:37:59 +00:00
if ( unlikely ( css - > key_size_dw ! = UOS_RSA_SCRATCH_COUNT ) ) {
dev_warn ( dev , " %s firmware %s: unexpected key size: %u != %u \n " ,
intel_uc_fw_type_repr ( uc_fw - > type ) , uc_fw - > path ,
css - > key_size_dw , UOS_RSA_SCRATCH_COUNT ) ;
err = - EPROTO ;
2017-10-04 15:33:25 +00:00
goto fail ;
}
uc_fw - > rsa_size = css - > key_size_dw * sizeof ( u32 ) ;
/* At least, it should have header, uCode and RSA. Size of all three. */
2019-07-26 18:42:10 +00:00
size = sizeof ( struct uc_css_header ) + uc_fw - > ucode_size + uc_fw - > rsa_size ;
2019-08-07 18:37:59 +00:00
if ( unlikely ( fw - > size < size ) ) {
dev_warn ( dev , " %s firmware %s: invalid size: %zu < %zu \n " ,
intel_uc_fw_type_repr ( uc_fw - > type ) , uc_fw - > path ,
fw - > size , size ) ;
2017-10-16 14:47:18 +00:00
err = - ENOEXEC ;
2017-10-04 15:33:25 +00:00
goto fail ;
}
2019-05-27 18:35:59 +00:00
/* Get version numbers from the CSS header */
2017-10-04 15:33:25 +00:00
switch ( uc_fw - > type ) {
case INTEL_UC_FW_TYPE_GUC :
2019-05-27 18:35:59 +00:00
uc_fw - > major_ver_found = FIELD_GET ( CSS_SW_VERSION_GUC_MAJOR ,
css - > sw_version ) ;
uc_fw - > minor_ver_found = FIELD_GET ( CSS_SW_VERSION_GUC_MINOR ,
css - > sw_version ) ;
2017-10-04 15:33:25 +00:00
break ;
case INTEL_UC_FW_TYPE_HUC :
2019-05-27 18:35:59 +00:00
uc_fw - > major_ver_found = FIELD_GET ( CSS_SW_VERSION_HUC_MAJOR ,
css - > sw_version ) ;
uc_fw - > minor_ver_found = FIELD_GET ( CSS_SW_VERSION_HUC_MINOR ,
css - > sw_version ) ;
2017-10-04 15:33:25 +00:00
break ;
default :
2017-10-16 14:47:18 +00:00
MISSING_CASE ( uc_fw - > type ) ;
break ;
2017-10-04 15:33:25 +00:00
}
2019-08-07 18:37:59 +00:00
if ( uc_fw - > major_ver_found ! = uc_fw - > major_ver_wanted | |
uc_fw - > minor_ver_found < uc_fw - > minor_ver_wanted ) {
dev_notice ( dev , " %s firmware %s: unexpected version: %u.%u != %u.%u \n " ,
intel_uc_fw_type_repr ( uc_fw - > type ) , uc_fw - > path ,
uc_fw - > major_ver_found , uc_fw - > minor_ver_found ,
uc_fw - > major_ver_wanted , uc_fw - > minor_ver_wanted ) ;
if ( ! intel_uc_fw_is_overridden ( uc_fw ) ) {
err = - ENOEXEC ;
goto fail ;
}
2017-10-04 15:33:25 +00:00
}
2019-07-25 21:03:14 +00:00
obj = i915_gem_object_create_shmem_from_data ( i915 , fw - > data , fw - > size ) ;
2017-10-04 15:33:25 +00:00
if ( IS_ERR ( obj ) ) {
err = PTR_ERR ( obj ) ;
goto fail ;
}
uc_fw - > obj = obj ;
uc_fw - > size = fw - > size ;
2019-07-24 17:18:09 -07:00
uc_fw - > status = INTEL_UC_FIRMWARE_AVAILABLE ;
2017-10-04 15:33:25 +00:00
2019-08-07 18:37:59 +00:00
DRM_DEV_DEBUG_DRIVER ( dev , " %s firmware %s: %s \n " ,
intel_uc_fw_type_repr ( uc_fw - > type ) , uc_fw - > path ,
intel_uc_fw_status_repr ( uc_fw - > status ) ) ;
2017-10-04 15:33:25 +00:00
release_firmware ( fw ) ;
2019-08-07 17:00:30 +00:00
return 0 ;
2017-10-04 15:33:25 +00:00
fail :
2019-08-07 18:37:59 +00:00
if ( err = = - ENOENT )
uc_fw - > status = INTEL_UC_FIRMWARE_MISSING ;
else
uc_fw - > status = INTEL_UC_FIRMWARE_ERROR ;
2017-10-16 14:47:18 +00:00
2019-08-07 18:37:59 +00:00
dev_notice ( dev , " %s firmware %s: fetch failed with error %d \n " ,
intel_uc_fw_type_repr ( uc_fw - > type ) , uc_fw - > path , err ) ;
dev_info ( dev , " %s firmware(s) can be downloaded from %s \n " ,
2017-10-16 14:47:19 +00:00
intel_uc_fw_type_repr ( uc_fw - > type ) , INTEL_UC_FIRMWARE_URL ) ;
2017-10-04 15:33:25 +00:00
release_firmware ( fw ) ; /* OK even if fw is NULL */
2019-08-07 17:00:30 +00:00
return err ;
2017-10-04 15:33:25 +00:00
}
2019-07-24 17:18:13 -07:00
static u32 uc_fw_ggtt_offset ( struct intel_uc_fw * uc_fw , struct i915_ggtt * ggtt )
{
struct drm_mm_node * node = & ggtt - > uc_fw ;
GEM_BUG_ON ( ! node - > allocated ) ;
GEM_BUG_ON ( upper_32_bits ( node - > start ) ) ;
GEM_BUG_ON ( upper_32_bits ( node - > start + node - > size - 1 ) ) ;
return lower_32_bits ( node - > start ) ;
}
2019-07-24 17:18:12 -07:00
static void intel_uc_fw_ggtt_bind ( struct intel_uc_fw * uc_fw ,
struct intel_gt * gt )
2019-04-19 16:00:13 -07:00
{
struct drm_i915_gem_object * obj = uc_fw - > obj ;
2019-07-24 17:18:12 -07:00
struct i915_ggtt * ggtt = gt - > ggtt ;
2019-04-19 16:00:13 -07:00
struct i915_vma dummy = {
2019-07-24 17:18:13 -07:00
. node . start = uc_fw_ggtt_offset ( uc_fw , ggtt ) ,
2019-04-19 16:00:13 -07:00
. node . size = obj - > base . size ,
. pages = obj - > mm . pages ,
. vm = & ggtt - > vm ,
} ;
GEM_BUG_ON ( ! i915_gem_object_has_pinned_pages ( obj ) ) ;
GEM_BUG_ON ( dummy . node . size > ggtt - > uc_fw . size ) ;
/* uc_fw->obj cache domains were not controlled across suspend */
drm_clflush_sg ( dummy . pages ) ;
ggtt - > vm . insert_entries ( & ggtt - > vm , & dummy , I915_CACHE_NONE , 0 ) ;
}
2019-07-24 17:18:12 -07:00
static void intel_uc_fw_ggtt_unbind ( struct intel_uc_fw * uc_fw ,
struct intel_gt * gt )
2019-04-19 16:00:13 -07:00
{
struct drm_i915_gem_object * obj = uc_fw - > obj ;
2019-07-24 17:18:12 -07:00
struct i915_ggtt * ggtt = gt - > ggtt ;
2019-07-24 17:18:13 -07:00
u64 start = uc_fw_ggtt_offset ( uc_fw , ggtt ) ;
2019-04-19 16:00:13 -07:00
ggtt - > vm . clear_range ( & ggtt - > vm , start , obj - > base . size ) ;
}
2019-07-24 17:18:13 -07:00
static int uc_fw_xfer ( struct intel_uc_fw * uc_fw , struct intel_gt * gt ,
u32 wopcm_offset , u32 dma_flags )
{
struct intel_uncore * uncore = gt - > uncore ;
u64 offset ;
int ret ;
2019-08-02 18:40:54 +00:00
ret = i915_inject_load_error ( gt - > i915 , - ETIMEDOUT ) ;
if ( ret )
return ret ;
2019-07-24 17:18:13 -07:00
intel_uncore_forcewake_get ( uncore , FORCEWAKE_ALL ) ;
/* Set the source address for the uCode */
2019-07-26 18:42:10 +00:00
offset = uc_fw_ggtt_offset ( uc_fw , gt - > ggtt ) ;
2019-07-24 17:18:13 -07:00
GEM_BUG_ON ( upper_32_bits ( offset ) & 0xFFFF0000 ) ;
intel_uncore_write_fw ( uncore , DMA_ADDR_0_LOW , lower_32_bits ( offset ) ) ;
intel_uncore_write_fw ( uncore , DMA_ADDR_0_HIGH , upper_32_bits ( offset ) ) ;
/* Set the DMA destination */
intel_uncore_write_fw ( uncore , DMA_ADDR_1_LOW , wopcm_offset ) ;
intel_uncore_write_fw ( uncore , DMA_ADDR_1_HIGH , DMA_ADDRESS_SPACE_WOPCM ) ;
/*
* Set the transfer size . The header plus uCode will be copied to WOPCM
* via DMA , excluding any other components
*/
intel_uncore_write_fw ( uncore , DMA_COPY_SIZE ,
2019-07-26 18:42:10 +00:00
sizeof ( struct uc_css_header ) + uc_fw - > ucode_size ) ;
2019-07-24 17:18:13 -07:00
/* Start the DMA */
intel_uncore_write_fw ( uncore , DMA_CTRL ,
_MASKED_BIT_ENABLE ( dma_flags | START_DMA ) ) ;
/* Wait for DMA to finish */
ret = intel_wait_for_register_fw ( uncore , DMA_CTRL , START_DMA , 0 , 100 ) ;
if ( ret )
dev_err ( gt - > i915 - > drm . dev , " DMA for %s fw failed, DMA_CTRL=%u \n " ,
intel_uc_fw_type_repr ( uc_fw - > type ) ,
intel_uncore_read_fw ( uncore , DMA_CTRL ) ) ;
/* Disable the bits once DMA is over */
intel_uncore_write_fw ( uncore , DMA_CTRL , _MASKED_BIT_DISABLE ( dma_flags ) ) ;
intel_uncore_forcewake_put ( uncore , FORCEWAKE_ALL ) ;
return ret ;
}
2017-10-16 14:47:21 +00:00
/**
* intel_uc_fw_upload - load uC firmware using custom loader
* @ uc_fw : uC firmware
2019-07-24 17:18:12 -07:00
* @ gt : the intel_gt structure
2019-07-24 17:18:13 -07:00
* @ wopcm_offset : destination offset in wopcm
* @ dma_flags : flags for flags for dma ctrl
2017-10-16 14:47:21 +00:00
*
2019-07-24 17:18:13 -07:00
* Loads uC firmware and updates internal flags .
2018-02-14 10:53:32 +00:00
*
* Return : 0 on success , non - zero on failure .
2017-10-16 14:47:21 +00:00
*/
2019-07-24 17:18:12 -07:00
int intel_uc_fw_upload ( struct intel_uc_fw * uc_fw , struct intel_gt * gt ,
2019-07-24 17:18:13 -07:00
u32 wopcm_offset , u32 dma_flags )
2017-10-16 14:47:21 +00:00
{
int err ;
2019-07-24 17:18:09 -07:00
/* make sure the status was cleared the last time we reset the uc */
GEM_BUG_ON ( intel_uc_fw_is_loaded ( uc_fw ) ) ;
2017-10-16 14:47:21 +00:00
2019-08-02 18:40:54 +00:00
err = i915_inject_load_error ( gt - > i915 , - ENOEXEC ) ;
if ( err )
return err ;
2019-07-24 17:18:09 -07:00
if ( ! intel_uc_fw_is_available ( uc_fw ) )
return - ENOEXEC ;
2019-08-02 18:40:54 +00:00
2017-10-16 14:47:21 +00:00
/* Call custom loader */
2019-07-24 17:18:12 -07:00
intel_uc_fw_ggtt_bind ( uc_fw , gt ) ;
2019-07-24 17:18:13 -07:00
err = uc_fw_xfer ( uc_fw , gt , wopcm_offset , dma_flags ) ;
2019-07-24 17:18:12 -07:00
intel_uc_fw_ggtt_unbind ( uc_fw , gt ) ;
2017-10-16 14:47:21 +00:00
if ( err )
goto fail ;
2019-07-24 17:18:09 -07:00
uc_fw - > status = INTEL_UC_FIRMWARE_TRANSFERRED ;
2019-08-11 19:51:31 +00:00
DRM_DEV_DEBUG_DRIVER ( gt - > i915 - > drm . dev , " %s firmware %s: %s \n " ,
intel_uc_fw_type_repr ( uc_fw - > type ) , uc_fw - > path ,
intel_uc_fw_status_repr ( uc_fw - > status ) ) ;
2017-10-16 14:47:21 +00:00
return 0 ;
fail :
2019-08-02 18:40:54 +00:00
i915_probe_error ( gt - > i915 , " Failed to load %s firmware %s (%d) \n " ,
intel_uc_fw_type_repr ( uc_fw - > type ) , uc_fw - > path ,
err ) ;
2019-07-24 17:18:09 -07:00
uc_fw - > status = INTEL_UC_FIRMWARE_FAIL ;
2017-10-16 14:47:21 +00:00
return err ;
}
2019-04-19 16:00:13 -07:00
int intel_uc_fw_init ( struct intel_uc_fw * uc_fw )
{
int err ;
2019-07-24 17:18:09 -07:00
/* this should happen before the load! */
GEM_BUG_ON ( intel_uc_fw_is_loaded ( uc_fw ) ) ;
if ( ! intel_uc_fw_is_available ( uc_fw ) )
2019-04-19 16:00:13 -07:00
return - ENOEXEC ;
err = i915_gem_object_pin_pages ( uc_fw - > obj ) ;
if ( err )
DRM_DEBUG_DRIVER ( " %s fw pin-pages err=%d \n " ,
intel_uc_fw_type_repr ( uc_fw - > type ) , err ) ;
return err ;
}
void intel_uc_fw_fini ( struct intel_uc_fw * uc_fw )
{
2019-07-24 17:18:09 -07:00
if ( ! intel_uc_fw_is_available ( uc_fw ) )
2019-04-19 16:00:13 -07:00
return ;
i915_gem_object_unpin_pages ( uc_fw - > obj ) ;
}
2017-10-04 15:33:25 +00:00
/**
2019-04-19 16:00:11 -07:00
* intel_uc_fw_cleanup_fetch - cleanup uC firmware
2017-10-04 15:33:25 +00:00
*
* @ uc_fw : uC firmware
*
* Cleans up uC firmware by releasing the firmware GEM obj .
*/
2019-04-19 16:00:11 -07:00
void intel_uc_fw_cleanup_fetch ( struct intel_uc_fw * uc_fw )
2017-10-04 15:33:25 +00:00
{
struct drm_i915_gem_object * obj ;
obj = fetch_and_zero ( & uc_fw - > obj ) ;
if ( obj )
i915_gem_object_put ( obj ) ;
2019-07-24 17:18:09 -07:00
uc_fw - > status = INTEL_UC_FIRMWARE_SELECTED ;
2017-10-04 15:33:25 +00:00
}
2017-10-17 09:44:49 +00:00
2019-07-24 17:18:10 -07:00
/**
* intel_uc_fw_copy_rsa - copy fw RSA to buffer
*
* @ uc_fw : uC firmware
* @ dst : dst buffer
* @ max_len : max number of bytes to copy
*
* Return : number of copied bytes .
*/
size_t intel_uc_fw_copy_rsa ( struct intel_uc_fw * uc_fw , void * dst , u32 max_len )
{
struct sg_table * pages = uc_fw - > obj - > mm . pages ;
u32 size = min_t ( u32 , uc_fw - > rsa_size , max_len ) ;
2019-07-26 18:42:12 +00:00
u32 offset = sizeof ( struct uc_css_header ) + uc_fw - > ucode_size ;
2019-07-24 17:18:10 -07:00
GEM_BUG_ON ( ! intel_uc_fw_is_available ( uc_fw ) ) ;
2019-07-26 18:42:12 +00:00
return sg_pcopy_to_buffer ( pages - > sgl , pages - > nents , dst , size , offset ) ;
2019-07-24 17:18:10 -07:00
}
2017-10-17 09:44:49 +00:00
/**
* intel_uc_fw_dump - dump information about uC firmware
* @ uc_fw : uC firmware
* @ p : the & drm_printer
*
* Pretty printer for uC firmware .
*/
2017-10-26 17:36:55 +00:00
void intel_uc_fw_dump ( const struct intel_uc_fw * uc_fw , struct drm_printer * p )
2017-10-17 09:44:49 +00:00
{
drm_printf ( p , " %s firmware: %s \n " ,
intel_uc_fw_type_repr ( uc_fw - > type ) , uc_fw - > path ) ;
2019-07-24 17:18:09 -07:00
drm_printf ( p , " \t status: %s \n " ,
intel_uc_fw_status_repr ( uc_fw - > status ) ) ;
2017-10-17 09:44:49 +00:00
drm_printf ( p , " \t version: wanted %u.%u, found %u.%u \n " ,
uc_fw - > major_ver_wanted , uc_fw - > minor_ver_wanted ,
uc_fw - > major_ver_found , uc_fw - > minor_ver_found ) ;
2019-07-26 18:42:11 +00:00
drm_printf ( p , " \t uCode: %u bytes \n " , uc_fw - > ucode_size ) ;
2019-07-26 18:42:12 +00:00
drm_printf ( p , " \t RSA: %u bytes \n " , uc_fw - > rsa_size ) ;
2017-10-17 09:44:49 +00:00
}