2018-03-13 17:32:50 -07:00
/*
* SPDX - License - Identifier : MIT
*
* Copyright © 2017 - 2018 Intel Corporation
*/
# include "intel_wopcm.h"
# include "i915_drv.h"
/**
* DOC : WOPCM Layout
*
* The layout of the WOPCM will be fixed after writing to GuC WOPCM size and
2018-03-22 16:59:22 -07:00
* offset registers whose values are calculated and determined by HuC / GuC
* firmware size and set of hardware requirements / restrictions as shown below :
2018-03-13 17:32:50 -07:00
*
2018-03-22 16:59:22 -07:00
* : :
*
* + = = = = = = = = = > + = = = = = = = = = = = = = = = = = = = = + < = = WOPCM Top
* ^ | HW contexts RSVD |
* | + = = = > + = = = = = = = = = = = = = = = = = = = = + < = = GuC WOPCM Top
* | ^ | |
* | | | |
* | | | |
* | GuC | |
* | WOPCM | |
* | Size + - - - - - - - - - - - - - - - - - - - - +
* WOPCM | | GuC FW RSVD |
* | | + - - - - - - - - - - - - - - - - - - - - +
* | | | GuC Stack RSVD |
* | | + - - - - - - - - - - - - - - - - - - - +
* | v | GuC WOPCM RSVD |
* | + = = = > + = = = = = = = = = = = = = = = = = = = = + < = = GuC WOPCM base
* | | WOPCM RSVD |
* | + - - - - - - - - - - - - - - - - - - - + < = = HuC Firmware Top
* v | HuC FW |
* + = = = = = = = = = > + = = = = = = = = = = = = = = = = = = = = + < = = WOPCM Base
2018-03-13 17:32:50 -07:00
*
* GuC accessible WOPCM starts at GuC WOPCM base and ends at GuC WOPCM top .
* The top part of the WOPCM is reserved for hardware contexts ( e . g . RC6
* context ) .
*/
2019-06-06 15:42:25 -07:00
/* Default WOPCM size is 2MB from Gen11, 1MB on previous platforms */
# define GEN11_WOPCM_SIZE SZ_2M
# define GEN9_WOPCM_SIZE SZ_1M
2018-03-13 17:32:50 -07:00
/* 16KB WOPCM (RSVD WOPCM) is reserved from HuC firmware top. */
2019-06-06 15:42:25 -07:00
# define WOPCM_RESERVED_SIZE SZ_16K
2018-03-13 17:32:50 -07:00
/* 16KB reserved at the beginning of GuC WOPCM. */
2019-06-06 15:42:25 -07:00
# define GUC_WOPCM_RESERVED SZ_16K
2018-03-13 17:32:50 -07:00
/* 8KB from GUC_WOPCM_RESERVED is reserved for GuC stack. */
2019-06-06 15:42:25 -07:00
# define GUC_WOPCM_STACK_RESERVED SZ_8K
2018-03-13 17:32:50 -07:00
/* GuC WOPCM Offset value needs to be aligned to 16KB. */
# define GUC_WOPCM_OFFSET_ALIGNMENT (1UL << GUC_WOPCM_OFFSET_SHIFT)
/* 24KB at the end of WOPCM is reserved for RC6 CTX on BXT. */
2019-06-06 15:42:25 -07:00
# define BXT_WOPCM_RC6_CTX_RESERVED (SZ_16K + SZ_8K)
2018-03-13 17:32:51 -07:00
/* 36KB WOPCM reserved at the end of WOPCM on CNL. */
2019-06-06 15:42:25 -07:00
# define CNL_WOPCM_HW_CTX_RESERVED (SZ_32K + SZ_4K)
2018-03-13 17:32:50 -07:00
/* 128KB from GUC_WOPCM_RESERVED is reserved for FW on Gen9. */
2019-06-06 15:42:25 -07:00
# define GEN9_GUC_FW_RESERVED SZ_128K
2018-03-13 17:32:50 -07:00
# define GEN9_GUC_WOPCM_OFFSET (GUC_WOPCM_RESERVED + GEN9_GUC_FW_RESERVED)
/**
* intel_wopcm_init_early ( ) - Early initialization of the WOPCM .
* @ wopcm : pointer to intel_wopcm .
*
* Setup the size of WOPCM which will be used by later on WOPCM partitioning .
*/
void intel_wopcm_init_early ( struct intel_wopcm * wopcm )
{
2019-06-06 15:42:25 -07:00
struct drm_i915_private * i915 = wopcm_to_i915 ( wopcm ) ;
if ( ! HAS_GUC ( i915 ) )
return ;
if ( INTEL_GEN ( i915 ) > = 11 )
wopcm - > size = GEN11_WOPCM_SIZE ;
else
wopcm - > size = GEN9_WOPCM_SIZE ;
2018-03-13 17:32:50 -07:00
DRM_DEBUG_DRIVER ( " WOPCM size: %uKiB \n " , wopcm - > size / 1024 ) ;
}
static inline u32 context_reserved_size ( struct drm_i915_private * i915 )
{
if ( IS_GEN9_LP ( i915 ) )
return BXT_WOPCM_RC6_CTX_RESERVED ;
2018-03-13 17:32:51 -07:00
else if ( INTEL_GEN ( i915 ) > = 10 )
return CNL_WOPCM_HW_CTX_RESERVED ;
2018-03-13 17:32:50 -07:00
else
return 0 ;
}
static inline int gen9_check_dword_gap ( u32 guc_wopcm_base , u32 guc_wopcm_size )
{
u32 offset ;
/*
* GuC WOPCM size shall be at least a dword larger than the offset from
* WOPCM base ( GuC WOPCM offset from WOPCM base + GEN9_GUC_WOPCM_OFFSET )
* due to hardware limitation on Gen9 .
*/
offset = guc_wopcm_base + GEN9_GUC_WOPCM_OFFSET ;
if ( offset > guc_wopcm_size | |
( guc_wopcm_size - offset ) < sizeof ( u32 ) ) {
DRM_ERROR ( " GuC WOPCM size %uKiB is too small. %uKiB needed. \n " ,
guc_wopcm_size / 1024 ,
( u32 ) ( offset + sizeof ( u32 ) ) / 1024 ) ;
return - E2BIG ;
}
return 0 ;
}
2018-03-13 17:32:52 -07:00
static inline int gen9_check_huc_fw_fits ( u32 guc_wopcm_size , u32 huc_fw_size )
{
/*
* On Gen9 & CNL A0 , hardware requires the total available GuC WOPCM
* size to be larger than or equal to HuC firmware size . Otherwise ,
* firmware uploading would fail .
*/
if ( huc_fw_size > guc_wopcm_size - GUC_WOPCM_RESERVED ) {
DRM_ERROR ( " HuC FW (%uKiB) won't fit in GuC WOPCM (%uKiB). \n " ,
huc_fw_size / 1024 ,
( guc_wopcm_size - GUC_WOPCM_RESERVED ) / 1024 ) ;
return - E2BIG ;
}
return 0 ;
}
2018-03-13 17:32:50 -07:00
static inline int check_hw_restriction ( struct drm_i915_private * i915 ,
2018-03-13 17:32:52 -07:00
u32 guc_wopcm_base , u32 guc_wopcm_size ,
u32 huc_fw_size )
2018-03-13 17:32:50 -07:00
{
int err = 0 ;
drm/i915: replace IS_GEN<N> with IS_GEN(..., N)
Define IS_GEN() similarly to our IS_GEN_RANGE(). but use gen instead of
gen_mask to do the comparison. Now callers can pass then gen as a parameter,
so we don't require one macro for each gen.
The following spatch was used to convert the users of these macros:
@@
expression e;
@@
(
- IS_GEN2(e)
+ IS_GEN(e, 2)
|
- IS_GEN3(e)
+ IS_GEN(e, 3)
|
- IS_GEN4(e)
+ IS_GEN(e, 4)
|
- IS_GEN5(e)
+ IS_GEN(e, 5)
|
- IS_GEN6(e)
+ IS_GEN(e, 6)
|
- IS_GEN7(e)
+ IS_GEN(e, 7)
|
- IS_GEN8(e)
+ IS_GEN(e, 8)
|
- IS_GEN9(e)
+ IS_GEN(e, 9)
|
- IS_GEN10(e)
+ IS_GEN(e, 10)
|
- IS_GEN11(e)
+ IS_GEN(e, 11)
)
v2: use IS_GEN rather than GT_GEN and compare to info.gen rather than
using the bitmask
Signed-off-by: Lucas De Marchi <lucas.demarchi@intel.com>
Reviewed-by: Jani Nikula <jani.nikula@intel.com>
Signed-off-by: Rodrigo Vivi <rodrigo.vivi@intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20181212181044.15886-2-lucas.demarchi@intel.com
2018-12-12 10:10:43 -08:00
if ( IS_GEN ( i915 , 9 ) )
2018-03-13 17:32:50 -07:00
err = gen9_check_dword_gap ( guc_wopcm_base , guc_wopcm_size ) ;
2018-03-13 17:32:52 -07:00
if ( ! err & &
drm/i915: replace IS_GEN<N> with IS_GEN(..., N)
Define IS_GEN() similarly to our IS_GEN_RANGE(). but use gen instead of
gen_mask to do the comparison. Now callers can pass then gen as a parameter,
so we don't require one macro for each gen.
The following spatch was used to convert the users of these macros:
@@
expression e;
@@
(
- IS_GEN2(e)
+ IS_GEN(e, 2)
|
- IS_GEN3(e)
+ IS_GEN(e, 3)
|
- IS_GEN4(e)
+ IS_GEN(e, 4)
|
- IS_GEN5(e)
+ IS_GEN(e, 5)
|
- IS_GEN6(e)
+ IS_GEN(e, 6)
|
- IS_GEN7(e)
+ IS_GEN(e, 7)
|
- IS_GEN8(e)
+ IS_GEN(e, 8)
|
- IS_GEN9(e)
+ IS_GEN(e, 9)
|
- IS_GEN10(e)
+ IS_GEN(e, 10)
|
- IS_GEN11(e)
+ IS_GEN(e, 11)
)
v2: use IS_GEN rather than GT_GEN and compare to info.gen rather than
using the bitmask
Signed-off-by: Lucas De Marchi <lucas.demarchi@intel.com>
Reviewed-by: Jani Nikula <jani.nikula@intel.com>
Signed-off-by: Rodrigo Vivi <rodrigo.vivi@intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20181212181044.15886-2-lucas.demarchi@intel.com
2018-12-12 10:10:43 -08:00
( IS_GEN ( i915 , 9 ) | | IS_CNL_REVID ( i915 , CNL_REVID_A0 , CNL_REVID_A0 ) ) )
2018-03-13 17:32:52 -07:00
err = gen9_check_huc_fw_fits ( guc_wopcm_size , huc_fw_size ) ;
2018-03-13 17:32:50 -07:00
return err ;
}
/**
* intel_wopcm_init ( ) - Initialize the WOPCM structure .
* @ wopcm : pointer to intel_wopcm .
*
* This function will partition WOPCM space based on GuC and HuC firmware sizes
* and will allocate max remaining for use by GuC . This function will also
* enforce platform dependent hardware restrictions on GuC WOPCM offset and
* size . It will fail the WOPCM init if any of these checks were failed , so that
* the following GuC firmware uploading would be aborted .
*
* Return : 0 on success , non - zero error code on failure .
*/
int intel_wopcm_init ( struct intel_wopcm * wopcm )
{
struct drm_i915_private * i915 = wopcm_to_i915 ( wopcm ) ;
2019-07-13 11:00:12 +01:00
u32 guc_fw_size = intel_uc_fw_get_upload_size ( & i915 - > gt . uc . guc . fw ) ;
u32 huc_fw_size = intel_uc_fw_get_upload_size ( & i915 - > gt . uc . huc . fw ) ;
2018-03-13 17:32:50 -07:00
u32 ctx_rsvd = context_reserved_size ( i915 ) ;
u32 guc_wopcm_base ;
u32 guc_wopcm_size ;
u32 guc_wopcm_rsvd ;
int err ;
2018-12-27 16:33:39 +02:00
if ( ! USES_GUC ( i915 ) )
2018-07-27 16:11:44 +02:00
return 0 ;
2018-03-13 17:32:50 -07:00
GEM_BUG_ON ( ! wopcm - > size ) ;
2019-07-12 13:24:27 +02:00
if ( i915_inject_probe_failure ( ) )
2018-07-27 16:11:47 +02:00
return - E2BIG ;
2018-03-13 17:32:50 -07:00
if ( guc_fw_size > = wopcm - > size ) {
DRM_ERROR ( " GuC FW (%uKiB) is too big to fit in WOPCM. " ,
guc_fw_size / 1024 ) ;
return - E2BIG ;
}
if ( huc_fw_size > = wopcm - > size ) {
DRM_ERROR ( " HuC FW (%uKiB) is too big to fit in WOPCM. " ,
huc_fw_size / 1024 ) ;
return - E2BIG ;
}
guc_wopcm_base = ALIGN ( huc_fw_size + WOPCM_RESERVED_SIZE ,
GUC_WOPCM_OFFSET_ALIGNMENT ) ;
if ( ( guc_wopcm_base + ctx_rsvd ) > = wopcm - > size ) {
DRM_ERROR ( " GuC WOPCM base (%uKiB) is too big. \n " ,
guc_wopcm_base / 1024 ) ;
return - E2BIG ;
}
guc_wopcm_size = wopcm - > size - guc_wopcm_base - ctx_rsvd ;
guc_wopcm_size & = GUC_WOPCM_SIZE_MASK ;
DRM_DEBUG_DRIVER ( " Calculated GuC WOPCM Region: [%uKiB, %uKiB) \n " ,
guc_wopcm_base / 1024 , guc_wopcm_size / 1024 ) ;
guc_wopcm_rsvd = GUC_WOPCM_RESERVED + GUC_WOPCM_STACK_RESERVED ;
if ( ( guc_fw_size + guc_wopcm_rsvd ) > guc_wopcm_size ) {
DRM_ERROR ( " Need %uKiB WOPCM for GuC, %uKiB available. \n " ,
( guc_fw_size + guc_wopcm_rsvd ) / 1024 ,
guc_wopcm_size / 1024 ) ;
return - E2BIG ;
}
2018-03-13 17:32:52 -07:00
err = check_hw_restriction ( i915 , guc_wopcm_base , guc_wopcm_size ,
huc_fw_size ) ;
2018-03-13 17:32:50 -07:00
if ( err )
return err ;
wopcm - > guc . base = guc_wopcm_base ;
wopcm - > guc . size = guc_wopcm_size ;
return 0 ;
}
2018-03-13 17:32:53 -07:00
2019-06-21 08:07:55 +01:00
static int
write_and_verify ( struct intel_gt * gt ,
i915_reg_t reg , u32 val , u32 mask , u32 locked_bit )
2018-03-13 17:32:53 -07:00
{
2019-06-21 08:07:55 +01:00
struct intel_uncore * uncore = gt - > uncore ;
2018-03-13 17:32:53 -07:00
u32 reg_val ;
GEM_BUG_ON ( val & ~ mask ) ;
2019-06-21 08:07:55 +01:00
intel_uncore_write ( uncore , reg , val ) ;
2018-03-13 17:32:53 -07:00
2019-06-21 08:07:55 +01:00
reg_val = intel_uncore_read ( uncore , reg ) ;
2018-03-13 17:32:53 -07:00
return ( reg_val & mask ) ! = ( val | locked_bit ) ? - EIO : 0 ;
}
/**
* intel_wopcm_init_hw ( ) - Setup GuC WOPCM registers .
* @ wopcm : pointer to intel_wopcm .
2019-06-21 14:16:40 +01:00
* @ gt : pointer to the containing GT
2018-03-13 17:32:53 -07:00
*
* Setup the GuC WOPCM size and offset registers with the calculated values . It
* will verify the register values to make sure the registers are locked with
* correct values .
*
* Return : 0 on success . - EIO if registers were locked with incorrect values .
*/
2019-06-21 08:07:55 +01:00
int intel_wopcm_init_hw ( struct intel_wopcm * wopcm , struct intel_gt * gt )
2018-03-13 17:32:53 -07:00
{
2019-06-21 08:07:55 +01:00
struct drm_i915_private * i915 = wopcm_to_i915 ( wopcm ) ;
struct intel_uncore * uncore = gt - > uncore ;
2018-03-13 17:32:53 -07:00
u32 huc_agent ;
u32 mask ;
int err ;
2019-06-21 08:07:55 +01:00
if ( ! USES_GUC ( i915 ) )
2018-03-13 17:32:53 -07:00
return 0 ;
2019-06-21 08:07:55 +01:00
GEM_BUG_ON ( ! HAS_GUC ( i915 ) ) ;
2018-03-13 17:32:53 -07:00
GEM_BUG_ON ( ! wopcm - > guc . size ) ;
GEM_BUG_ON ( ! wopcm - > guc . base ) ;
2019-06-21 08:07:55 +01:00
err = write_and_verify ( gt , GUC_WOPCM_SIZE , wopcm - > guc . size ,
2018-03-13 17:32:53 -07:00
GUC_WOPCM_SIZE_MASK | GUC_WOPCM_SIZE_LOCKED ,
GUC_WOPCM_SIZE_LOCKED ) ;
if ( err )
goto err_out ;
2019-06-21 08:07:55 +01:00
huc_agent = USES_HUC ( i915 ) ? HUC_LOADING_AGENT_GUC : 0 ;
2018-03-13 17:32:53 -07:00
mask = GUC_WOPCM_OFFSET_MASK | GUC_WOPCM_OFFSET_VALID | huc_agent ;
2019-06-21 08:07:55 +01:00
err = write_and_verify ( gt , DMA_GUC_WOPCM_OFFSET ,
2018-03-13 17:32:53 -07:00
wopcm - > guc . base | huc_agent , mask ,
GUC_WOPCM_OFFSET_VALID ) ;
if ( err )
goto err_out ;
return 0 ;
err_out :
DRM_ERROR ( " Failed to init WOPCM registers: \n " ) ;
DRM_ERROR ( " DMA_GUC_WOPCM_OFFSET=%#x \n " ,
2019-06-21 08:07:55 +01:00
intel_uncore_read ( uncore , DMA_GUC_WOPCM_OFFSET ) ) ;
DRM_ERROR ( " GUC_WOPCM_SIZE=%#x \n " ,
intel_uncore_read ( uncore , GUC_WOPCM_SIZE ) ) ;
2018-03-13 17:32:53 -07:00
return err ;
}