2019-08-12 09:29:35 +00:00
// SPDX-License-Identifier: MIT
2017-10-04 15:33:25 +00:00
/*
2019-08-12 09:29:35 +00:00
* Copyright © 2016 - 2019 Intel Corporation
2017-10-04 15:33:25 +00:00
*/
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"
2020-03-26 11:11:18 -07:00
static inline struct intel_gt *
____uc_fw_to_gt ( struct intel_uc_fw * uc_fw , enum intel_uc_fw_type type )
2019-08-13 08:15:59 +00:00
{
2020-03-26 11:11:18 -07:00
if ( type = = INTEL_UC_FW_TYPE_GUC )
2019-08-13 08:15:59 +00:00
return container_of ( uc_fw , struct intel_gt , uc . guc . fw ) ;
2020-03-26 11:11:18 -07:00
GEM_BUG_ON ( type ! = INTEL_UC_FW_TYPE_HUC ) ;
2019-08-13 08:15:59 +00:00
return container_of ( uc_fw , struct intel_gt , uc . huc . fw ) ;
}
2020-03-26 11:11:18 -07:00
static inline struct intel_gt * __uc_fw_to_gt ( struct intel_uc_fw * uc_fw )
{
GEM_BUG_ON ( uc_fw - > status = = INTEL_UC_FIRMWARE_UNINITIALIZED ) ;
return ____uc_fw_to_gt ( uc_fw , uc_fw - > type ) ;
}
2019-12-11 12:45:47 +00:00
# ifdef CONFIG_DRM_I915_DEBUG_GUC
2019-08-13 08:15:59 +00:00
void intel_uc_fw_change_status ( struct intel_uc_fw * uc_fw ,
enum intel_uc_fw_status status )
{
uc_fw - > __status = status ;
2020-04-02 14:48:12 +03:00
drm_dbg ( & __uc_fw_to_gt ( uc_fw ) - > i915 - > drm ,
" %s firmware -> %s \n " ,
intel_uc_fw_type_repr ( uc_fw - > type ) ,
status = = INTEL_UC_FIRMWARE_SELECTED ?
uc_fw - > path : intel_uc_fw_status_repr ( status ) ) ;
2019-08-13 08:15:59 +00:00
}
# endif
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 .
2019-10-25 17:35:06 -07:00
*
* TGL 35.2 is interface - compatible with 33.0 for previous Gens . The deltas
* between 33.0 and 35.2 are only related to new additions to support new Gen12
* features .
2020-05-04 15:52:08 -07:00
*
* Note that RKL uses the same firmware as TGL .
2019-07-24 17:18:08 -07:00
*/
# define INTEL_UC_FIRMWARE_DEFS(fw_def, guc_def, huc_def) \
2020-08-13 13:00:29 -07:00
fw_def ( ROCKETLAKE , 0 , guc_def ( tgl , 35 , 2 , 0 ) , huc_def ( tgl , 7 , 5 , 0 ) ) \
fw_def ( TIGERLAKE , 0 , guc_def ( tgl , 35 , 2 , 0 ) , huc_def ( tgl , 7 , 5 , 0 ) ) \
2019-09-19 13:12:03 -07:00
fw_def ( ELKHARTLAKE , 0 , guc_def ( ehl , 33 , 0 , 4 ) , huc_def ( ehl , 9 , 0 , 0 ) ) \
fw_def ( ICELAKE , 0 , guc_def ( icl , 33 , 0 , 0 ) , huc_def ( icl , 9 , 0 , 0 ) ) \
2020-06-02 15:05:40 +01:00
fw_def ( COMETLAKE , 5 , guc_def ( cml , 33 , 0 , 0 ) , huc_def ( cml , 4 , 0 , 0 ) ) \
2019-09-19 13:12:03 -07:00
fw_def ( COFFEELAKE , 0 , guc_def ( kbl , 33 , 0 , 0 ) , huc_def ( kbl , 4 , 0 , 0 ) ) \
fw_def ( GEMINILAKE , 0 , guc_def ( glk , 33 , 0 , 0 ) , huc_def ( glk , 4 , 0 , 0 ) ) \
fw_def ( KABYLAKE , 0 , guc_def ( kbl , 33 , 0 , 0 ) , huc_def ( kbl , 4 , 0 , 0 ) ) \
fw_def ( BROXTON , 0 , guc_def ( bxt , 33 , 0 , 0 ) , huc_def ( bxt , 2 , 0 , 0 ) ) \
fw_def ( SKYLAKE , 0 , guc_def ( skl , 33 , 0 , 0 ) , huc_def ( skl , 2 , 0 , 0 ) )
2019-07-24 17:18:08 -07:00
2019-09-19 13:12:03 -07:00
# define __MAKE_UC_FW_PATH(prefix_, name_, major_, minor_, patch_) \
2019-07-24 17:18:08 -07:00
" i915/ " \
__stringify ( prefix_ ) name_ \
2019-09-19 13:12:03 -07:00
__stringify ( major_ ) " . " \
__stringify ( minor_ ) " . " \
2019-07-24 17:18:08 -07:00
__stringify ( patch_ ) " .bin "
# define MAKE_GUC_FW_PATH(prefix_, major_, minor_, patch_) \
2019-09-19 13:12:03 -07:00
__MAKE_UC_FW_PATH ( prefix_ , " _guc_ " , major_ , minor_ , patch_ )
2019-07-24 17:18:08 -07:00
# define MAKE_HUC_FW_PATH(prefix_, major_, minor_, bld_num_) \
2019-09-19 13:12:03 -07:00
__MAKE_UC_FW_PATH ( prefix_ , " _huc_ " , major_ , minor_ , bld_num_ )
2019-07-24 17:18:08 -07:00
/* 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
2020-06-18 18:04:02 +03:00
__uc_fw_auto_select ( struct drm_i915_private * i915 , struct intel_uc_fw * uc_fw )
2019-07-24 17:18:08 -07:00
{
static const struct uc_fw_platform_requirement fw_blobs [ ] = {
INTEL_UC_FIRMWARE_DEFS ( MAKE_FW_LIST , GUC_FW_BLOB , HUC_FW_BLOB )
} ;
2020-06-18 18:04:02 +03:00
enum intel_platform p = INTEL_INFO ( i915 ) - > platform ;
u8 rev = INTEL_REVID ( i915 ) ;
2019-07-24 17:18:08 -07:00
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 */
2020-06-18 18:04:02 +03:00
if ( i915 - > params . enable_guc = = - 1 & & p < INTEL_ICELAKE )
2019-07-31 22:33:19 +00:00
uc_fw - > path = NULL ;
}
2020-06-18 18:04:02 +03:00
static const char * __override_guc_firmware_path ( struct drm_i915_private * i915 )
2019-07-31 22:33:19 +00:00
{
2020-06-18 18:04:02 +03:00
if ( i915 - > params . enable_guc & ( ENABLE_GUC_SUBMISSION |
ENABLE_GUC_LOAD_HUC ) )
return i915 - > params . guc_firmware_path ;
2019-07-31 22:33:19 +00:00
return " " ;
}
2020-06-18 18:04:02 +03:00
static const char * __override_huc_firmware_path ( struct drm_i915_private * i915 )
2019-07-31 22:33:19 +00:00
{
2020-06-18 18:04:02 +03:00
if ( i915 - > params . enable_guc & ENABLE_GUC_LOAD_HUC )
return i915 - > params . huc_firmware_path ;
2019-07-31 22:33:19 +00:00
return " " ;
2019-07-24 17:18:08 -07:00
}
2020-06-18 18:04:02 +03:00
static void __uc_fw_user_override ( struct drm_i915_private * i915 , 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 :
2020-06-18 18:04:02 +03:00
path = __override_guc_firmware_path ( i915 ) ;
2019-07-24 17:18:08 -07:00
break ;
case INTEL_UC_FW_TYPE_HUC :
2020-06-18 18:04:02 +03:00
path = __override_huc_firmware_path ( i915 ) ;
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
*
* 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 ,
2020-03-26 11:11:18 -07:00
enum intel_uc_fw_type type )
2019-07-24 17:18:08 -07:00
{
2020-03-26 11:11:18 -07:00
struct drm_i915_private * i915 = ____uc_fw_to_gt ( uc_fw , type ) - > i915 ;
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 ;
2020-03-26 11:11:18 -07:00
if ( HAS_GT_UC ( i915 ) ) {
2020-06-18 18:04:02 +03:00
__uc_fw_auto_select ( i915 , uc_fw ) ;
__uc_fw_user_override ( i915 , uc_fw ) ;
2019-08-07 18:37:59 +00:00
}
2019-07-24 17:18:08 -07:00
2019-08-16 20:56:58 +00:00
intel_uc_fw_change_status ( uc_fw , uc_fw - > path ? * uc_fw - > path ?
2019-08-13 08:15:59 +00:00
INTEL_UC_FIRMWARE_SELECTED :
2019-08-16 20:56:58 +00:00
INTEL_UC_FIRMWARE_DISABLED :
2019-08-13 08:15:59 +00:00
INTEL_UC_FIRMWARE_NOT_SUPPORTED ) ;
2019-07-24 17:18:08 -07:00
}
2019-12-11 12:45:47 +00:00
static void __force_fw_fetch_failures ( struct intel_uc_fw * uc_fw , int e )
2019-08-07 18:37:59 +00:00
{
2019-12-11 12:45:47 +00:00
struct drm_i915_private * i915 = __uc_fw_to_gt ( uc_fw ) - > i915 ;
2019-08-07 18:37:59 +00:00
bool user = e = = - EINVAL ;
2019-10-29 11:20:35 +01:00
if ( i915_inject_probe_error ( i915 , e ) ) {
2019-08-07 18:37:59 +00:00
/* non-existing blob */
uc_fw - > path = " <invalid> " ;
uc_fw - > user_overridden = user ;
2019-10-29 11:20:35 +01:00
} else if ( i915_inject_probe_error ( i915 , e ) ) {
2019-08-07 18:37:59 +00:00
/* require next major version */
uc_fw - > major_ver_wanted + = 1 ;
uc_fw - > minor_ver_wanted = 0 ;
uc_fw - > user_overridden = user ;
2019-10-29 11:20:35 +01:00
} else if ( i915_inject_probe_error ( i915 , e ) ) {
2019-08-07 18:37:59 +00:00
/* require next minor version */
uc_fw - > minor_ver_wanted + = 1 ;
uc_fw - > user_overridden = user ;
2019-10-29 11:20:35 +01:00
} else if ( uc_fw - > major_ver_wanted & &
i915_inject_probe_error ( i915 , e ) ) {
2019-08-07 18:37:59 +00:00
/* require prev major version */
uc_fw - > major_ver_wanted - = 1 ;
uc_fw - > minor_ver_wanted = 0 ;
uc_fw - > user_overridden = user ;
2019-10-29 11:20:35 +01:00
} else if ( uc_fw - > minor_ver_wanted & &
i915_inject_probe_error ( i915 , e ) ) {
2019-08-07 18:37:59 +00:00
/* require prev minor version - hey, this should work! */
uc_fw - > minor_ver_wanted - = 1 ;
uc_fw - > user_overridden = user ;
2019-10-29 11:20:35 +01:00
} else if ( user & & i915_inject_probe_error ( i915 , e ) ) {
2019-08-07 18:37:59 +00:00
/* 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
*
* 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-12-11 12:45:47 +00:00
int intel_uc_fw_fetch ( struct intel_uc_fw * uc_fw )
2017-10-04 15:33:25 +00:00
{
2019-12-11 12:45:47 +00:00
struct drm_i915_private * i915 = __uc_fw_to_gt ( uc_fw ) - > i915 ;
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-08-16 10:54:57 +00:00
GEM_BUG_ON ( ! i915 - > wopcm . size ) ;
2019-08-16 20:56:58 +00:00
GEM_BUG_ON ( ! intel_uc_fw_is_enabled ( uc_fw ) ) ;
2019-07-13 11:00:08 +01:00
2019-10-29 11:20:35 +01:00
err = i915_inject_probe_error ( i915 , - ENXIO ) ;
2019-07-24 17:18:09 -07:00
if ( err )
2020-02-18 14:33:21 -08:00
goto fail ;
2017-10-04 15:33:25 +00:00
2019-12-11 12:45:47 +00:00
__force_fw_fetch_failures ( uc_fw , - EINVAL ) ;
__force_fw_fetch_failures ( uc_fw , - ESTALE ) ;
2019-08-07 18:37:59 +00:00
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 ) ) ) {
2020-04-02 14:48:19 +03:00
drm_warn ( & i915 - > drm , " %s firmware %s: invalid size: %zu < %zu \n " ,
2019-08-07 18:37:59 +00:00
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 ) ) ) {
2020-04-02 14:48:19 +03:00
drm_warn ( & i915 - > drm ,
2019-08-07 18:37:59 +00:00
" %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 ) ) {
2020-04-02 14:48:19 +03:00
drm_warn ( & i915 - > drm , " %s firmware %s: unexpected key size: %u != %u \n " ,
2019-08-07 18:37:59 +00:00
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 ) ) {
2020-04-02 14:48:19 +03:00
drm_warn ( & i915 - > drm , " %s firmware %s: invalid size: %zu < %zu \n " ,
2019-08-07 18:37:59 +00:00
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-08-16 10:54:57 +00:00
/* Sanity check whether this fw is not larger than whole WOPCM memory */
size = __intel_uc_fw_get_upload_size ( uc_fw ) ;
if ( unlikely ( size > = i915 - > wopcm . size ) ) {
2020-04-02 14:48:19 +03:00
drm_warn ( & i915 - > drm , " %s firmware %s: invalid size: %zu > %zu \n " ,
2019-08-16 10:54:57 +00:00
intel_uc_fw_type_repr ( uc_fw - > type ) , uc_fw - > path ,
size , ( size_t ) i915 - > wopcm . size ) ;
err = - E2BIG ;
goto fail ;
}
2019-05-27 18:35:59 +00:00
/* Get version numbers from the CSS header */
2019-09-25 15:21:21 -07:00
uc_fw - > major_ver_found = FIELD_GET ( CSS_SW_VERSION_UC_MAJOR ,
css - > sw_version ) ;
uc_fw - > minor_ver_found = FIELD_GET ( CSS_SW_VERSION_UC_MINOR ,
css - > sw_version ) ;
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 ) {
2020-04-02 14:48:19 +03:00
drm_notice ( & i915 - > drm , " %s firmware %s: unexpected version: %u.%u != %u.%u \n " ,
2019-08-07 18:37:59 +00:00
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-08-13 08:15:59 +00:00
intel_uc_fw_change_status ( uc_fw , INTEL_UC_FIRMWARE_AVAILABLE ) ;
2019-08-07 18:37:59 +00:00
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-13 08:15:59 +00:00
intel_uc_fw_change_status ( uc_fw , err = = - ENOENT ?
INTEL_UC_FIRMWARE_MISSING :
INTEL_UC_FIRMWARE_ERROR ) ;
2017-10-16 14:47:18 +00:00
2020-04-02 14:48:19 +03:00
drm_notice ( & i915 - > drm , " %s firmware %s: fetch failed with error %d \n " ,
2019-08-07 18:37:59 +00:00
intel_uc_fw_type_repr ( uc_fw - > type ) , uc_fw - > path , err ) ;
2020-04-02 14:48:19 +03:00
drm_info ( & i915 - > drm , " %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-12-11 12:45:49 +00:00
static u32 uc_fw_ggtt_offset ( struct intel_uc_fw * uc_fw )
2019-07-24 17:18:13 -07:00
{
2019-12-11 12:45:49 +00:00
struct i915_ggtt * ggtt = __uc_fw_to_gt ( uc_fw ) - > ggtt ;
2019-07-24 17:18:13 -07:00
struct drm_mm_node * node = & ggtt - > uc_fw ;
2019-10-03 22:00:58 +01:00
GEM_BUG_ON ( ! drm_mm_node_allocated ( node ) ) ;
2019-07-24 17:18:13 -07:00
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-12-11 12:45:48 +00:00
static void uc_fw_bind_ggtt ( struct intel_uc_fw * uc_fw )
2019-04-19 16:00:13 -07:00
{
struct drm_i915_gem_object * obj = uc_fw - > obj ;
2019-12-11 12:45:48 +00:00
struct i915_ggtt * ggtt = __uc_fw_to_gt ( uc_fw ) - > ggtt ;
2019-04-19 16:00:13 -07:00
struct i915_vma dummy = {
2019-12-11 12:45:49 +00:00
. node . start = uc_fw_ggtt_offset ( uc_fw ) ,
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-12-11 12:45:48 +00:00
static void uc_fw_unbind_ggtt ( struct intel_uc_fw * uc_fw )
2019-04-19 16:00:13 -07:00
{
struct drm_i915_gem_object * obj = uc_fw - > obj ;
2019-12-11 12:45:48 +00:00
struct i915_ggtt * ggtt = __uc_fw_to_gt ( uc_fw ) - > ggtt ;
2019-12-11 12:45:49 +00:00
u64 start = uc_fw_ggtt_offset ( uc_fw ) ;
2019-04-19 16:00:13 -07:00
ggtt - > vm . clear_range ( & ggtt - > vm , start , obj - > base . size ) ;
}
2019-12-11 12:45:48 +00:00
static int uc_fw_xfer ( struct intel_uc_fw * uc_fw , u32 dst_offset , u32 dma_flags )
2019-07-24 17:18:13 -07:00
{
2019-12-11 12:45:48 +00:00
struct intel_gt * gt = __uc_fw_to_gt ( uc_fw ) ;
2019-07-24 17:18:13 -07:00
struct intel_uncore * uncore = gt - > uncore ;
u64 offset ;
int ret ;
2019-10-29 11:20:35 +01:00
ret = i915_inject_probe_error ( gt - > i915 , - ETIMEDOUT ) ;
2019-08-02 18:40:54 +00:00
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-12-11 12:45:49 +00:00
offset = uc_fw_ggtt_offset ( uc_fw ) ;
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 */
2019-12-11 12:45:48 +00:00
intel_uncore_write_fw ( uncore , DMA_ADDR_1_LOW , dst_offset ) ;
2019-07-24 17:18:13 -07:00
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 )
2020-04-02 14:48:19 +03:00
drm_err ( & gt - > i915 - > drm , " DMA for %s fw failed, DMA_CTRL=%u \n " ,
2019-07-24 17:18:13 -07:00
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-12-11 12:45:48 +00:00
* @ dst_offset : destination offset
2019-07-24 17:18:13 -07:00
* @ 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-12-11 12:45:48 +00:00
int intel_uc_fw_upload ( struct intel_uc_fw * uc_fw , u32 dst_offset , u32 dma_flags )
2017-10-16 14:47:21 +00:00
{
2019-12-11 12:45:48 +00:00
struct intel_gt * gt = __uc_fw_to_gt ( uc_fw ) ;
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-10-29 11:20:35 +01:00
err = i915_inject_probe_error ( gt - > i915 , - ENOEXEC ) ;
2019-08-02 18:40:54 +00:00
if ( err )
return err ;
2020-02-18 14:33:26 -08:00
if ( ! intel_uc_fw_is_loadable ( uc_fw ) )
2019-07-24 17:18:09 -07:00
return - ENOEXEC ;
2019-08-02 18:40:54 +00:00
2017-10-16 14:47:21 +00:00
/* Call custom loader */
2019-12-11 12:45:48 +00:00
uc_fw_bind_ggtt ( uc_fw ) ;
err = uc_fw_xfer ( uc_fw , dst_offset , dma_flags ) ;
uc_fw_unbind_ggtt ( uc_fw ) ;
2017-10-16 14:47:21 +00:00
if ( err )
goto fail ;
2019-08-13 08:15:59 +00:00
intel_uc_fw_change_status ( uc_fw , INTEL_UC_FIRMWARE_TRANSFERRED ) ;
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-08-13 08:15:59 +00:00
intel_uc_fw_change_status ( uc_fw , 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 ) ;
2019-08-17 13:11:43 +00:00
if ( err ) {
2019-04-19 16:00:13 -07:00
DRM_DEBUG_DRIVER ( " %s fw pin-pages err=%d \n " ,
intel_uc_fw_type_repr ( uc_fw - > type ) , err ) ;
2019-08-17 13:11:43 +00:00
intel_uc_fw_change_status ( uc_fw , INTEL_UC_FIRMWARE_FAIL ) ;
}
2019-04-19 16:00:13 -07:00
return err ;
}
void intel_uc_fw_fini ( struct intel_uc_fw * uc_fw )
{
2020-02-18 14:33:26 -08:00
if ( i915_gem_object_has_pinned_pages ( uc_fw - > obj ) )
i915_gem_object_unpin_pages ( uc_fw - > obj ) ;
intel_uc_fw_change_status ( uc_fw , INTEL_UC_FIRMWARE_AVAILABLE ) ;
2019-04-19 16:00:13 -07:00
}
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
{
2019-08-17 13:11:42 +00:00
if ( ! intel_uc_fw_is_available ( uc_fw ) )
return ;
2017-10-04 15:33:25 +00:00
2019-08-17 13:11:42 +00:00
i915_gem_object_put ( fetch_and_zero ( & uc_fw - > obj ) ) ;
2017-10-04 15:33:25 +00:00
2019-08-13 08:15:59 +00:00
intel_uc_fw_change_status ( uc_fw , 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
}