diff mbox

[v7,3/6] drm/i915/guc: Implement dynamic GuC WOPCM offset and size

Message ID 1516325372-24448-3-git-send-email-yaodong.li@intel.com (mailing list archive)
State New, archived
Headers show

Commit Message

Jackie Li Jan. 19, 2018, 1:29 a.m. UTC
Hardware may have specific restrictions on GuC WOPCM size
versus HuC firmware size. With static GuC WOPCM size,
there's no way to adjust the GuC WOPCM partition size based on
the actual HuC firmware size, so that GuC/HuC loading failure
would occur even if there was enough WOPCM space for both
GuC and HuC firmware.

This patch enables the dynamic calculation of the GuC WOPCM
aperture size used by GuC and HuC firmware. GuC WOPCM offset is
set to HuC size + reserved WOPCM size. GuC WOPCM size is set to
total WOPCM size - GuC WOPCM offset - RC6CTX size. In this case,
GuC WOPCM offset will be updated based on the size of HuC firmware
while GuC WOPCM size will be set to use all the remaining WOPCM space.

v2:
 - Removed intel_wopcm_init (Ville/Sagar/Joonas)
 - Renamed and Moved the intel_wopcm_partition into intel_guc (Sagar)
 - Removed unnecessary function calls (Joonas)
 - Init GuC WOPCM partition as soon as firmware fetching is completed

v3:
 - Fixed indentation issues (Chris)
 - Removed layering violation code (Chris/Michal)
 - Created separat files for GuC wopcm code  (Michal)
 - Used inline function to avoid code duplication (Michal)

v4:
 - Preset the GuC WOPCM top during early GuC init (Chris)
 - Fail intel_uc_init_hw() as soon as GuC WOPCM partitioning failed

v5:
 - Moved GuC DMA WOPCM register updating code into intel_guc_wopcm.c
 - Took care of the locking status before writing to GuC DMA
   Write-Once registers. (Joonas)

v6:
 - Made sure the GuC WOPCM size to be multiple of 4K (4K aligned)

Cc: Michal Wajdeczko <michal.wajdeczko@intel.com>
Cc: Sagar Arun Kamble <sagar.a.kamble@intel.com>
Cc: Sujaritha Sundaresan <sujaritha.sundaresan@intel.com>
Cc: Daniele Ceraolo Spurio <daniele.ceraolospurio@intel.com>
Cc: John Spotswood <john.a.spotswood@intel.com>
Cc: Oscar Mateo <oscar.mateo@intel.com>
Cc: Chris Wilson <chris@chris-wilson.co.uk>
Cc: Joonas Lahtinen <joonas.lahtinen@linux.intel.com>
Signed-off-by: Jackie Li <yaodong.li@intel.com>
---
 drivers/gpu/drm/i915/i915_gem_context.c |   9 +--
 drivers/gpu/drm/i915/intel_guc.c        |   5 +-
 drivers/gpu/drm/i915/intel_guc.h        |  12 ++--
 drivers/gpu/drm/i915/intel_guc_reg.h    |   1 +
 drivers/gpu/drm/i915/intel_guc_wopcm.c  | 108 +++++++++++++++++++++++++++++---
 drivers/gpu/drm/i915/intel_guc_wopcm.h  |  40 ++++++++++--
 drivers/gpu/drm/i915/intel_huc.c        |   2 +-
 drivers/gpu/drm/i915/intel_uc.c         |  11 +++-
 drivers/gpu/drm/i915/intel_uc_fw.c      |  11 +++-
 drivers/gpu/drm/i915/intel_uc_fw.h      |  16 +++++
 10 files changed, 183 insertions(+), 32 deletions(-)

Comments

sagar.a.kamble@intel.com Feb. 1, 2018, 8:38 a.m. UTC | #1
On 1/19/2018 6:59 AM, Jackie Li wrote:
> Hardware may have specific restrictions on GuC WOPCM size
It would be good if you can tell about Gen9/CNL restriction briefly here.
> versus HuC firmware size. With static GuC WOPCM size,
> there's no way to adjust the GuC WOPCM partition size based on
> the actual HuC firmware size, so that GuC/HuC loading failure
> would occur even if there was enough WOPCM space for both
> GuC and HuC firmware.
>
> This patch enables the dynamic calculation of the GuC WOPCM
> aperture size used by GuC and HuC firmware.
we are also calculating for HuC?
>   GuC WOPCM offset is
> set to HuC size + reserved WOPCM size. GuC WOPCM size is set to
> total WOPCM size - GuC WOPCM offset - RC6CTX size. In this case,
> GuC WOPCM offset will be updated based on the size of HuC firmware
> while GuC WOPCM size will be set to use all the remaining WOPCM space.
>
> v2:
>   - Removed intel_wopcm_init (Ville/Sagar/Joonas)
>   - Renamed and Moved the intel_wopcm_partition into intel_guc (Sagar)
>   - Removed unnecessary function calls (Joonas)
>   - Init GuC WOPCM partition as soon as firmware fetching is completed
>
> v3:
>   - Fixed indentation issues (Chris)
>   - Removed layering violation code (Chris/Michal)
>   - Created separat files for GuC wopcm code  (Michal)
>   - Used inline function to avoid code duplication (Michal)
>
> v4:
>   - Preset the GuC WOPCM top during early GuC init (Chris)
>   - Fail intel_uc_init_hw() as soon as GuC WOPCM partitioning failed
>
> v5:
>   - Moved GuC DMA WOPCM register updating code into intel_guc_wopcm.c
>   - Took care of the locking status before writing to GuC DMA
>     Write-Once registers. (Joonas)
>
> v6:
>   - Made sure the GuC WOPCM size to be multiple of 4K (4K aligned)
>
> Cc: Michal Wajdeczko <michal.wajdeczko@intel.com>
> Cc: Sagar Arun Kamble <sagar.a.kamble@intel.com>
> Cc: Sujaritha Sundaresan <sujaritha.sundaresan@intel.com>
> Cc: Daniele Ceraolo Spurio <daniele.ceraolospurio@intel.com>
> Cc: John Spotswood <john.a.spotswood@intel.com>
> Cc: Oscar Mateo <oscar.mateo@intel.com>
> Cc: Chris Wilson <chris@chris-wilson.co.uk>
> Cc: Joonas Lahtinen <joonas.lahtinen@linux.intel.com>
> Signed-off-by: Jackie Li <yaodong.li@intel.com>
> ---
>   drivers/gpu/drm/i915/i915_gem_context.c |   9 +--
>   drivers/gpu/drm/i915/intel_guc.c        |   5 +-
>   drivers/gpu/drm/i915/intel_guc.h        |  12 ++--
>   drivers/gpu/drm/i915/intel_guc_reg.h    |   1 +
>   drivers/gpu/drm/i915/intel_guc_wopcm.c  | 108 +++++++++++++++++++++++++++++---
>   drivers/gpu/drm/i915/intel_guc_wopcm.h  |  40 ++++++++++--
>   drivers/gpu/drm/i915/intel_huc.c        |   2 +-
>   drivers/gpu/drm/i915/intel_uc.c         |  11 +++-
>   drivers/gpu/drm/i915/intel_uc_fw.c      |  11 +++-
>   drivers/gpu/drm/i915/intel_uc_fw.h      |  16 +++++
>   10 files changed, 183 insertions(+), 32 deletions(-)
>
> diff --git a/drivers/gpu/drm/i915/i915_gem_context.c b/drivers/gpu/drm/i915/i915_gem_context.c
> index 648e753..b485794 100644
> --- a/drivers/gpu/drm/i915/i915_gem_context.c
> +++ b/drivers/gpu/drm/i915/i915_gem_context.c
> @@ -312,12 +312,13 @@ __create_hw_context(struct drm_i915_private *dev_priv,
>   	ctx->desc_template =
>   		default_desc_template(dev_priv, dev_priv->mm.aliasing_ppgtt);
>   
> -	/* GuC requires the ring to be placed above GUC_WOPCM_TOP. If GuC is not
> -	 * present or not in use we still need a small bias as ring wraparound
> -	 * at offset 0 sometimes hangs. No idea why.
> +	/*
> +	 * GuC requires the ring to be placed above GuC WOPCM top. If GuC is not
> +-	 * present or not in use we still need a small bias as ring wraparound
> +-	 * at offset 0 sometimes hangs. No idea why.
+-?
>   	 */
>   	if (USES_GUC(dev_priv))
> -		ctx->ggtt_offset_bias = GUC_WOPCM_TOP;
> +		ctx->ggtt_offset_bias = dev_priv->guc.wopcm.top;
>   	else
>   		ctx->ggtt_offset_bias = I915_GTT_PAGE_SIZE;
>   
> diff --git a/drivers/gpu/drm/i915/intel_guc.c b/drivers/gpu/drm/i915/intel_guc.c
> index e70885b..3521beb 100644
> --- a/drivers/gpu/drm/i915/intel_guc.c
> +++ b/drivers/gpu/drm/i915/intel_guc.c
> @@ -64,6 +64,7 @@ void intel_guc_init_early(struct intel_guc *guc)
>   {
>   	intel_guc_fw_init_early(guc);
>   	intel_guc_ct_init_early(&guc->ct);
> +	intel_guc_wopcm_init_early(&guc->wopcm);
>   
>   	mutex_init(&guc->send_mutex);
>   	guc->send = intel_guc_send_nop;
> @@ -473,7 +474,7 @@ int intel_guc_resume(struct drm_i915_private *dev_priv)
>    * This is a wrapper to create an object for use with the GuC. In order to
>    * use it inside the GuC, an object needs to be pinned lifetime, so we allocate
>    * both some backing storage and a range inside the Global GTT. We must pin
> - * it in the GGTT somewhere other than than [0, GUC_WOPCM_TOP) because that
> + * it in the GGTT somewhere other than than [0, GuC WOPCM top) because that
>    * range is reserved inside GuC.
>    *
>    * Return:	A i915_vma if successful, otherwise an ERR_PTR.
> @@ -494,7 +495,7 @@ struct i915_vma *intel_guc_allocate_vma(struct intel_guc *guc, u32 size)
>   		goto err;
>   
>   	ret = i915_vma_pin(vma, 0, PAGE_SIZE,
> -			   PIN_GLOBAL | PIN_OFFSET_BIAS | GUC_WOPCM_TOP);
> +			   PIN_GLOBAL | PIN_OFFSET_BIAS | guc->wopcm.top);
>   	if (ret) {
>   		vma = ERR_PTR(ret);
>   		goto err;
> diff --git a/drivers/gpu/drm/i915/intel_guc.h b/drivers/gpu/drm/i915/intel_guc.h
> index b7e2a18..ea35911 100644
> --- a/drivers/gpu/drm/i915/intel_guc.h
> +++ b/drivers/gpu/drm/i915/intel_guc.h
> @@ -49,6 +49,7 @@ struct intel_guc {
>   	struct intel_uc_fw fw;
>   	struct intel_guc_log log;
>   	struct intel_guc_ct ct;
> +	struct intel_guc_wopcm wopcm;
>   
>   	/* Log snapshot if GuC errors during load */
>   	struct drm_i915_gem_object *load_err_log;
> @@ -105,10 +106,10 @@ static inline void intel_guc_notify(struct intel_guc *guc)
>    * @guc: intel guc.
>    * @vma: i915 graphics virtual memory area.
>    *
> - * 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
> - * 512K. In order to exclude 0-512K address space from GGTT, all gfx objects
> - * used by GuC is pinned with PIN_OFFSET_BIAS along with size of WOPCM.
> + * GuC does not allow any gfx GGTT address that falls into range
> + * [0, GuC WOPCM top), which is reserved for Boot ROM, SRAM and WOPCM.
> + * All gfx objects used by GuC is pinned with PIN_OFFSET_BIAS along with
> + * top of WOPCM.
>    *
>    * Return: GGTT offset that meets the GuC gfx address requirement.
>    */
> @@ -117,7 +118,8 @@ static inline u32 intel_guc_ggtt_offset(struct intel_guc *guc,
>   {
>   	u32 offset = i915_ggtt_offset(vma);
>   
> -	GEM_BUG_ON(offset < GUC_WOPCM_TOP);
> +	GEM_BUG_ON(!guc->wopcm.valid);
> +	GEM_BUG_ON(offset < guc->wopcm.top);
>   	GEM_BUG_ON(range_overflows_t(u64, offset, vma->size, GUC_GGTT_TOP));
>   
>   	return offset;
> diff --git a/drivers/gpu/drm/i915/intel_guc_reg.h b/drivers/gpu/drm/i915/intel_guc_reg.h
> index 1f52fb8..9109be7 100644
> --- a/drivers/gpu/drm/i915/intel_guc_reg.h
> +++ b/drivers/gpu/drm/i915/intel_guc_reg.h
> @@ -75,6 +75,7 @@
>   
>   /* Defines WOPCM space available to GuC firmware */
>   #define GUC_WOPCM_SIZE			_MMIO(0xc050)
> +#define GUC_WOPCM_SIZE_MASK		(0xfffff000)
>   
>   /* GuC addresses above GUC_GGTT_TOP also don't map through the GTT */
>   #define GUC_GGTT_TOP			0xFEE00000
> diff --git a/drivers/gpu/drm/i915/intel_guc_wopcm.c b/drivers/gpu/drm/i915/intel_guc_wopcm.c
> index 87643a0..0532714 100644
> --- a/drivers/gpu/drm/i915/intel_guc_wopcm.c
> +++ b/drivers/gpu/drm/i915/intel_guc_wopcm.c
> @@ -25,23 +25,111 @@
>   #include "intel_guc_wopcm.h"
>   #include "i915_drv.h"
>   
> +static inline u32 guc_reserved_wopcm_size(struct intel_guc *guc)
> +{
> +	struct drm_i915_private *i915 = guc_to_i915(guc);
> +
> +	/* On BXT, the top of WOPCM is reserved for RC6 context */
> +	if (IS_GEN9_LP(i915))
> +		return BXT_WOPCM_RC6_RESERVED;
Keep the name as BXT_GUC_WOPCM_RC6_RESERVED as earlier. And we seem to 
be changing
the size of this from 64KB to 24KB. Please update commit message also.
> +
> +	return 0;
> +}
> +
> +static inline int gen9_wocpm_size_check(struct drm_i915_private *i915)
> +{
> +	struct intel_guc_wopcm *wopcm = &i915->guc.wopcm;
> +	u32 wopcm_base;
> +	u32 delta;
> +
> +	/*
> +	 * Check hardware restriction on Gen9
> +	 * GuC WOPCM size is at least 4 bytes larger than GuC WOPCM base due
> +	 * to hardware limitation on Gen9.
> +	 */
> +	wopcm_base = wopcm->offset + GEN9_GUC_WOPCM_OFFSET;
> +	if (unlikely(wopcm_base > wopcm->size))
Comment for this restriction?
> +		return -E2BIG;
> +
> +	delta = wopcm->size - wopcm_base;
> +	if (unlikely(delta < GEN9_GUC_WOPCM_DELTA))
> +		return -E2BIG;
> +
> +	return 0;
> +}
> +
> +static inline int guc_wopcm_size_check(struct intel_guc *guc)
> +{
> +	struct drm_i915_private *i915 = guc_to_i915(guc);
> +
> +	if (IS_GEN9(i915))
> +		return gen9_wocpm_size_check(i915);
> +
> +	return 0;
> +}
> +
>   /*
> - * intel_guc_wopcm_size() - Get the size of GuC WOPCM.
> + * intel_guc_wopcm_init() - Initialize the GuC WOPCM partition.
>    * @guc: intel guc.
> + * @guc_fw_size: size of GuC firmware.
> + * @huc_fw_size: size of HuC firmware.
>    *
> - * Get the platform specific GuC WOPCM size.
> + * This function tries to initialize the WOPCM partition based on HuC firmware
> + * size and the reserved WOPCM memory size.
>    *
> - * Return: size of the GuC WOPCM.
> + * Return: 0 on success, non-zero error code on failure.
>    */
> -u32 intel_guc_wopcm_size(struct intel_guc *guc)
> +int intel_guc_wopcm_init(struct intel_guc *guc, u32 guc_fw_size,
> +			 u32 huc_fw_size)
>   {
> -	struct drm_i915_private *i915 = guc_to_i915(guc);
> +	u32 reserved = guc_reserved_wopcm_size(guc);
> +	u32 offset, size, top;
> +	int err;
>   
> -	u32 wopcm_size = GUC_WOPCM_TOP;
> +	if (guc->wopcm.valid)
> +		return 0;
>   
> -	/* On BXT, the top of WOPCM is reserved for RC6 context */
> -	if (IS_GEN9_LP(i915))
> -		wopcm_size -= BXT_GUC_WOPCM_RC6_RESERVED;
> +	if (!guc_fw_size)
> +		return -EINVAL;
> +
> +	if (reserved >= WOPCM_DEFAULT_SIZE)
> +		return -E2BIG;
> +
> +	offset = huc_fw_size + WOPCM_RESERVED_SIZE;
> +	if (offset >= WOPCM_DEFAULT_SIZE)
> +		return -E2BIG;
> +
> +	/* Hardware requires GuC WOPCM offset needs to be 16K aligned. */
> +	offset = ALIGN(offset, WOPCM_OFFSET_ALIGNMENT);
> +	if ((offset + reserved) >= WOPCM_DEFAULT_SIZE)
> +		return -E2BIG;
> +
> +	top = WOPCM_DEFAULT_SIZE - offset;
> +	size = top - reserved;
> +
> +	/* GuC WOPCM size must be 4K aligned. */
> +	size &= GUC_WOPCM_SIZE_MASK;
> +
ALIGN(size, PAGE_SIZE)? Can avoid this new macro.
If you want to stay with GUC_WOPCM_SIZE_MASK, then that macro needs to 
be in guc_wopcm.h
> +	/*
> +	 * GuC size needs to be less than or equal to GuC WOPCM size.
> +	 * Need extra 8K stack for GuC.
> +	 */
> +	if ((guc_fw_size + GUC_WOPCM_STACK_RESERVED) > size)
> +		return -E2BIG;
> +
> +	guc->wopcm.offset = offset;
> +	guc->wopcm.size = size;
> +	guc->wopcm.top = top;
> +
> +	/* Check platform specific restrictions */
> +	err = guc_wopcm_size_check(guc);
> +	if (err)
> +		return err;
> +
> +	guc->wopcm.valid = true;
> +
> +	DRM_DEBUG_DRIVER("GuC WOPCM offset %dKB, size %dKB, top %dKB\n",
> +			 offset >> 10, size >> 10, top >> 10);
>   
> -	return wopcm_size;
> +	return 0;
>   }
> diff --git a/drivers/gpu/drm/i915/intel_guc_wopcm.h b/drivers/gpu/drm/i915/intel_guc_wopcm.h
> index 595fb1c..352cf3d 100644
> --- a/drivers/gpu/drm/i915/intel_guc_wopcm.h
> +++ b/drivers/gpu/drm/i915/intel_guc_wopcm.h
> @@ -29,11 +29,41 @@
>   
>   struct intel_guc;
>   
> -#define   GUC_WOPCM_OFFSET_VALUE	0x80000	/* 512KB */
> -/* GuC addresses below GUC_WOPCM_TOP don't map through the GTT */
> -#define GUC_WOPCM_TOP			(0x80 << 12)	/* 512KB */
> -#define BXT_GUC_WOPCM_RC6_RESERVED	(0x10 << 12)	/* 64KB  */
> +/* Default WOPCM size 1MB */
> +#define WOPCM_DEFAULT_SIZE		(0x1 << 20)
> +/* Reserved WOPCM size 16KB */
> +#define WOPCM_RESERVED_SIZE		(0x4000)
WOPCM_BEGIN_RESERVED_SIZE?
> +/* GUC WOPCM Offset need to be 16KB aligned */
> +#define WOPCM_OFFSET_ALIGNMENT		(0x4000)
> +/* 8KB stack reserved for GuC FW*/
> +#define GUC_WOPCM_STACK_RESERVED	(0x2000)
GUC_WOPCM_BEGIN_RESERVED_STACK_SIZE?
> +/* 24KB WOPCM reserved for RC6 CTX on BXT */
> +#define BXT_WOPCM_RC6_RESERVED		(0x6000)
BXT_GUC_WOPCM_END_RC6_RESERVED?
Layout in comments would simplify understanding. :)
Or just comments as initial 16kb is reserved in wopcm then huc can be 
loaded,
post that 8kb is needed for GuC stack and then Guc is to be loaded till 
point
from where rc6 context resides.
Distinguishing whether reserved from begin or end helps understand the 
code logic.
>   
> -u32 intel_guc_wopcm_size(struct intel_guc *guc);
> +#define GEN9_GUC_WOPCM_DELTA		4
> +#define GEN9_GUC_WOPCM_OFFSET		(0x24000)
> +
> +struct intel_guc_wopcm {
> +	u32 offset;
> +	u32 size;
> +	u32 top;
> +	bool valid;
> +};
> +
> +/*
kernel doc comment format "/**"
> + * intel_guc_wopcm_init_early() - Early initialization of the GuC WOPCM.
> + * @wopcm: GuC WOPCM.
> + *
> + * Setup the GuC WOPCM top to the top of the overall WOPCM. This will guarantee
> + * that the allocation of the GuC accessible objects won't fall into WOPCM when
> + * GuC partition isn't present.
> + *
> + */
> +static inline void intel_guc_wopcm_init_early(struct intel_guc_wopcm *wopcm)
> +{
> +	wopcm->top = WOPCM_DEFAULT_SIZE;
I think instead of hardcoding we can have it derived from 
"reserved_total" in i915_gem_init_stolen.
Will need to init possibly during intel_uc_init_misc or we can derive 
reserved_total here itself.
Also it seems we need to reduce usage of WOPCM_DEFAULT_SIZE and rely on 
wopcm->top in
places needing the check.
> +}
> +
> +int intel_guc_wopcm_init(struct intel_guc *guc, u32 guc_size, u32 huc_size);
>   
>   #endif
> diff --git a/drivers/gpu/drm/i915/intel_huc.c b/drivers/gpu/drm/i915/intel_huc.c
> index aed9c1c..dc6a6c6 100644
> --- a/drivers/gpu/drm/i915/intel_huc.c
> +++ b/drivers/gpu/drm/i915/intel_huc.c
> @@ -206,7 +206,7 @@ int intel_huc_auth(struct intel_huc *huc)
>   		return -ENOEXEC;
>   
>   	vma = i915_gem_object_ggtt_pin(huc->fw.obj, NULL, 0, 0,
> -				PIN_OFFSET_BIAS | GUC_WOPCM_TOP);
> +				PIN_OFFSET_BIAS | guc->wopcm.top);
>   	if (IS_ERR(vma)) {
>   		ret = PTR_ERR(vma);
>   		DRM_ERROR("HuC: Failed to pin huc fw object %d\n", ret);
> diff --git a/drivers/gpu/drm/i915/intel_uc.c b/drivers/gpu/drm/i915/intel_uc.c
> index e9d0568..b5a08d1 100644
> --- a/drivers/gpu/drm/i915/intel_uc.c
> +++ b/drivers/gpu/drm/i915/intel_uc.c
> @@ -263,6 +263,9 @@ void intel_uc_fini_wq(struct drm_i915_private *dev_priv)
>   int intel_uc_init(struct drm_i915_private *dev_priv)
>   {
>   	struct intel_guc *guc = &dev_priv->guc;
> +	struct intel_huc *huc = &dev_priv->huc;
> +	u32 guc_fw_size = intel_uc_fw_get_size(&guc->fw);
> +	u32 huc_fw_size = intel_uc_fw_get_size(&huc->fw);
>   	int ret;
>   
>   	if (!USES_GUC(dev_priv))
> @@ -271,6 +274,10 @@ int intel_uc_init(struct drm_i915_private *dev_priv)
>   	if (!HAS_GUC(dev_priv))
>   		return -ENODEV;
>   
> +	ret = intel_guc_wopcm_init(guc, guc_fw_size, huc_fw_size);
> +	if (ret)
> +		return ret;
> +
>   	ret = intel_guc_init(guc);
>   	if (ret)
>   		return ret;
> @@ -320,9 +327,9 @@ int intel_uc_init_hw(struct drm_i915_private *dev_priv)
>   	gen9_reset_guc_interrupts(dev_priv);
>   
>   	/* init WOPCM */
> -	I915_WRITE(GUC_WOPCM_SIZE, intel_guc_wopcm_size(guc));
> +	I915_WRITE(GUC_WOPCM_SIZE, guc->wopcm.size);
>   	I915_WRITE(DMA_GUC_WOPCM_OFFSET,
> -		   GUC_WOPCM_OFFSET_VALUE | HUC_LOADING_AGENT_GUC);
> +		   guc->wopcm.offset | HUC_LOADING_AGENT_GUC);
>   
>   	/* WaEnableuKernelHeaderValidFix:skl */
>   	/* WaEnableGuCBootHashCheckNotSet:skl,bxt,kbl */
> diff --git a/drivers/gpu/drm/i915/intel_uc_fw.c b/drivers/gpu/drm/i915/intel_uc_fw.c
> index 24945cf..791263a 100644
> --- a/drivers/gpu/drm/i915/intel_uc_fw.c
> +++ b/drivers/gpu/drm/i915/intel_uc_fw.c
> @@ -95,9 +95,13 @@ void intel_uc_fw_fetch(struct drm_i915_private *dev_priv,
>   	uc_fw->ucode_offset = uc_fw->header_offset + uc_fw->header_size;
>   	uc_fw->ucode_size = (css->size_dw - css->header_size_dw) * sizeof(u32);
>   
> -	/* Header and uCode will be loaded to WOPCM */
> +	/*
> +	 * Header and uCode will be loaded to WOPCM
> +	 * Only check the size against the overall available WOPCM here. Will
> +	 * continue to check the size during WOPCM partition calculation.
> +	 */
>   	size = uc_fw->header_size + uc_fw->ucode_size;
> -	if (size > intel_guc_wopcm_size(&dev_priv->guc)) {
> +	if (size > WOPCM_DEFAULT_SIZE) {
>   		DRM_WARN("%s: Firmware is too large to fit in WOPCM\n",
>   			 intel_uc_fw_type_repr(uc_fw->type));
>   		err = -E2BIG;
> @@ -207,6 +211,7 @@ int intel_uc_fw_upload(struct intel_uc_fw *uc_fw,
>   		       int (*xfer)(struct intel_uc_fw *uc_fw,
>   				   struct i915_vma *vma))
>   {
> +	struct drm_i915_private *i915 = to_i915(uc_fw->obj->base.dev);
>   	struct i915_vma *vma;
>   	int err;
>   
> @@ -230,7 +235,7 @@ int intel_uc_fw_upload(struct intel_uc_fw *uc_fw,
>   	}
>   
>   	vma = i915_gem_object_ggtt_pin(uc_fw->obj, NULL, 0, 0,
> -				       PIN_OFFSET_BIAS | GUC_WOPCM_TOP);
> +				       PIN_OFFSET_BIAS | i915->guc.wopcm.top);
>   	if (IS_ERR(vma)) {
>   		err = PTR_ERR(vma);
>   		DRM_DEBUG_DRIVER("%s fw ggtt-pin err=%d\n",
> diff --git a/drivers/gpu/drm/i915/intel_uc_fw.h b/drivers/gpu/drm/i915/intel_uc_fw.h
> index d5fd460..d00d888 100644
> --- a/drivers/gpu/drm/i915/intel_uc_fw.h
> +++ b/drivers/gpu/drm/i915/intel_uc_fw.h
> @@ -115,6 +115,22 @@ static inline bool intel_uc_fw_is_selected(struct intel_uc_fw *uc_fw)
>   	return uc_fw->path != NULL;
>   }
>   
> +/*
> + * intel_uc_fw_get_size() - Get the size of the firmware.
> + * @uc_fw: intel_uc_fw structure.
> + *
> + * Get the size of the firmware that will be placed in WOPCM.
> + *
> + * Return: Zero on invalid firmware status. actual size on success.
> + */
> +static inline u32 intel_uc_fw_get_size(struct intel_uc_fw *uc_fw)
> +{
> +	if (uc_fw->fetch_status != INTEL_UC_FIRMWARE_SUCCESS)
> +		return 0;
> +
> +	return uc_fw->header_size + uc_fw->ucode_size;
> +}
> +
>   void intel_uc_fw_fetch(struct drm_i915_private *dev_priv,
>   		       struct intel_uc_fw *uc_fw);
>   int intel_uc_fw_upload(struct intel_uc_fw *uc_fw,
Jackie Li Feb. 1, 2018, 9:51 p.m. UTC | #2
On 02/01/2018 12:38 AM, Sagar Arun Kamble wrote:
>
>
> On 1/19/2018 6:59 AM, Jackie Li wrote:
>> Hardware may have specific restrictions on GuC WOPCM size
> It would be good if you can tell about Gen9/CNL restriction briefly here.
>> versus HuC firmware size. With static GuC WOPCM size,
>> there's no way to adjust the GuC WOPCM partition size based on
>> the actual HuC firmware size, so that GuC/HuC loading failure
>> would occur even if there was enough WOPCM space for both
>> GuC and HuC firmware.
>>
>> This patch enables the dynamic calculation of the GuC WOPCM
>> aperture size used by GuC and HuC firmware.
> we are also calculating for HuC?
Strictly speaking, we are calculating the GuC WOPCM offset based on
GuC & HuC firmware sizes. Will make it clearer. Thanks.

>> +    offset = huc_fw_size + WOPCM_RESERVED_SIZE;
>> +    if (offset >= WOPCM_DEFAULT_SIZE)
>> +        return -E2BIG;
>> +
>> +    /* Hardware requires GuC WOPCM offset needs to be 16K aligned. */
>> +    offset = ALIGN(offset, WOPCM_OFFSET_ALIGNMENT);
>> +    if ((offset + reserved) >= WOPCM_DEFAULT_SIZE)
>> +        return -E2BIG;
>> +
>> +    top = WOPCM_DEFAULT_SIZE - offset;
>> +    size = top - reserved;
>> +
>> +    /* GuC WOPCM size must be 4K aligned. */
>> +    size &= GUC_WOPCM_SIZE_MASK;
>> +
> ALIGN(size, PAGE_SIZE)? Can avoid this new macro.
> If you want to stay with GUC_WOPCM_SIZE_MASK, then that macro needs to 
> be in guc_wopcm.h
I'd like to go with GUC_WOPCM_SIZE_MASK here since there's no sign that 
it should be related to
page size. *Align* seems not accurate here since I actually wanted to 
trim the size to 4k boundary,
will update the comments. Thanks!
sagar.a.kamble@intel.com Feb. 2, 2018, 5:22 a.m. UTC | #3
On 2/2/2018 3:21 AM, Yaodong Li wrote:
>
> On 02/01/2018 12:38 AM, Sagar Arun Kamble wrote:
>>
>>
>> On 1/19/2018 6:59 AM, Jackie Li wrote:
>>> Hardware may have specific restrictions on GuC WOPCM size
>> It would be good if you can tell about Gen9/CNL restriction briefly 
>> here.
>>> versus HuC firmware size. With static GuC WOPCM size,
>>> there's no way to adjust the GuC WOPCM partition size based on
>>> the actual HuC firmware size, so that GuC/HuC loading failure
>>> would occur even if there was enough WOPCM space for both
>>> GuC and HuC firmware.
>>>
>>> This patch enables the dynamic calculation of the GuC WOPCM
>>> aperture size used by GuC and HuC firmware.
>> we are also calculating for HuC?
> Strictly speaking, we are calculating the GuC WOPCM offset based on
> GuC & HuC firmware sizes. Will make it clearer. Thanks.
>
>>> +    offset = huc_fw_size + WOPCM_RESERVED_SIZE;
>>> +    if (offset >= WOPCM_DEFAULT_SIZE)
>>> +        return -E2BIG;
>>> +
>>> +    /* Hardware requires GuC WOPCM offset needs to be 16K aligned. */
>>> +    offset = ALIGN(offset, WOPCM_OFFSET_ALIGNMENT);
>>> +    if ((offset + reserved) >= WOPCM_DEFAULT_SIZE)
>>> +        return -E2BIG;
>>> +
>>> +    top = WOPCM_DEFAULT_SIZE - offset;
>>> +    size = top - reserved;
>>> +
>>> +    /* GuC WOPCM size must be 4K aligned. */
>>> +    size &= GUC_WOPCM_SIZE_MASK;
>>> +
>> ALIGN(size, PAGE_SIZE)? Can avoid this new macro.
>> If you want to stay with GUC_WOPCM_SIZE_MASK, then that macro needs 
>> to be in guc_wopcm.h
> I'd like to go with GUC_WOPCM_SIZE_MASK here since there's no sign 
> that it should be related to
> page size. *Align* seems not accurate here since I actually wanted to 
> trim the size to 4k boundary,
> will update the comments. Thanks!
Need to update comment though. /* GuC WOPCM size must be multiple of 4K 
pages */

Align does not suit here. We could have used "& ~PAGE_MASK" but okay 
with G_W_S_M too.
size being absolute here helps. had it been offset starting from 0 we 
would have needed extra logic.
>
>
diff mbox

Patch

diff --git a/drivers/gpu/drm/i915/i915_gem_context.c b/drivers/gpu/drm/i915/i915_gem_context.c
index 648e753..b485794 100644
--- a/drivers/gpu/drm/i915/i915_gem_context.c
+++ b/drivers/gpu/drm/i915/i915_gem_context.c
@@ -312,12 +312,13 @@  __create_hw_context(struct drm_i915_private *dev_priv,
 	ctx->desc_template =
 		default_desc_template(dev_priv, dev_priv->mm.aliasing_ppgtt);
 
-	/* GuC requires the ring to be placed above GUC_WOPCM_TOP. If GuC is not
-	 * present or not in use we still need a small bias as ring wraparound
-	 * at offset 0 sometimes hangs. No idea why.
+	/*
+	 * GuC requires the ring to be placed above GuC WOPCM top. If GuC is not
+-	 * present or not in use we still need a small bias as ring wraparound
+-	 * at offset 0 sometimes hangs. No idea why.
 	 */
 	if (USES_GUC(dev_priv))
-		ctx->ggtt_offset_bias = GUC_WOPCM_TOP;
+		ctx->ggtt_offset_bias = dev_priv->guc.wopcm.top;
 	else
 		ctx->ggtt_offset_bias = I915_GTT_PAGE_SIZE;
 
diff --git a/drivers/gpu/drm/i915/intel_guc.c b/drivers/gpu/drm/i915/intel_guc.c
index e70885b..3521beb 100644
--- a/drivers/gpu/drm/i915/intel_guc.c
+++ b/drivers/gpu/drm/i915/intel_guc.c
@@ -64,6 +64,7 @@  void intel_guc_init_early(struct intel_guc *guc)
 {
 	intel_guc_fw_init_early(guc);
 	intel_guc_ct_init_early(&guc->ct);
+	intel_guc_wopcm_init_early(&guc->wopcm);
 
 	mutex_init(&guc->send_mutex);
 	guc->send = intel_guc_send_nop;
@@ -473,7 +474,7 @@  int intel_guc_resume(struct drm_i915_private *dev_priv)
  * This is a wrapper to create an object for use with the GuC. In order to
  * use it inside the GuC, an object needs to be pinned lifetime, so we allocate
  * both some backing storage and a range inside the Global GTT. We must pin
- * it in the GGTT somewhere other than than [0, GUC_WOPCM_TOP) because that
+ * it in the GGTT somewhere other than than [0, GuC WOPCM top) because that
  * range is reserved inside GuC.
  *
  * Return:	A i915_vma if successful, otherwise an ERR_PTR.
@@ -494,7 +495,7 @@  struct i915_vma *intel_guc_allocate_vma(struct intel_guc *guc, u32 size)
 		goto err;
 
 	ret = i915_vma_pin(vma, 0, PAGE_SIZE,
-			   PIN_GLOBAL | PIN_OFFSET_BIAS | GUC_WOPCM_TOP);
+			   PIN_GLOBAL | PIN_OFFSET_BIAS | guc->wopcm.top);
 	if (ret) {
 		vma = ERR_PTR(ret);
 		goto err;
diff --git a/drivers/gpu/drm/i915/intel_guc.h b/drivers/gpu/drm/i915/intel_guc.h
index b7e2a18..ea35911 100644
--- a/drivers/gpu/drm/i915/intel_guc.h
+++ b/drivers/gpu/drm/i915/intel_guc.h
@@ -49,6 +49,7 @@  struct intel_guc {
 	struct intel_uc_fw fw;
 	struct intel_guc_log log;
 	struct intel_guc_ct ct;
+	struct intel_guc_wopcm wopcm;
 
 	/* Log snapshot if GuC errors during load */
 	struct drm_i915_gem_object *load_err_log;
@@ -105,10 +106,10 @@  static inline void intel_guc_notify(struct intel_guc *guc)
  * @guc: intel guc.
  * @vma: i915 graphics virtual memory area.
  *
- * 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
- * 512K. In order to exclude 0-512K address space from GGTT, all gfx objects
- * used by GuC is pinned with PIN_OFFSET_BIAS along with size of WOPCM.
+ * GuC does not allow any gfx GGTT address that falls into range
+ * [0, GuC WOPCM top), which is reserved for Boot ROM, SRAM and WOPCM.
+ * All gfx objects used by GuC is pinned with PIN_OFFSET_BIAS along with
+ * top of WOPCM.
  *
  * Return: GGTT offset that meets the GuC gfx address requirement.
  */
@@ -117,7 +118,8 @@  static inline u32 intel_guc_ggtt_offset(struct intel_guc *guc,
 {
 	u32 offset = i915_ggtt_offset(vma);
 
-	GEM_BUG_ON(offset < GUC_WOPCM_TOP);
+	GEM_BUG_ON(!guc->wopcm.valid);
+	GEM_BUG_ON(offset < guc->wopcm.top);
 	GEM_BUG_ON(range_overflows_t(u64, offset, vma->size, GUC_GGTT_TOP));
 
 	return offset;
diff --git a/drivers/gpu/drm/i915/intel_guc_reg.h b/drivers/gpu/drm/i915/intel_guc_reg.h
index 1f52fb8..9109be7 100644
--- a/drivers/gpu/drm/i915/intel_guc_reg.h
+++ b/drivers/gpu/drm/i915/intel_guc_reg.h
@@ -75,6 +75,7 @@ 
 
 /* Defines WOPCM space available to GuC firmware */
 #define GUC_WOPCM_SIZE			_MMIO(0xc050)
+#define GUC_WOPCM_SIZE_MASK		(0xfffff000)
 
 /* GuC addresses above GUC_GGTT_TOP also don't map through the GTT */
 #define GUC_GGTT_TOP			0xFEE00000
diff --git a/drivers/gpu/drm/i915/intel_guc_wopcm.c b/drivers/gpu/drm/i915/intel_guc_wopcm.c
index 87643a0..0532714 100644
--- a/drivers/gpu/drm/i915/intel_guc_wopcm.c
+++ b/drivers/gpu/drm/i915/intel_guc_wopcm.c
@@ -25,23 +25,111 @@ 
 #include "intel_guc_wopcm.h"
 #include "i915_drv.h"
 
+static inline u32 guc_reserved_wopcm_size(struct intel_guc *guc)
+{
+	struct drm_i915_private *i915 = guc_to_i915(guc);
+
+	/* On BXT, the top of WOPCM is reserved for RC6 context */
+	if (IS_GEN9_LP(i915))
+		return BXT_WOPCM_RC6_RESERVED;
+
+	return 0;
+}
+
+static inline int gen9_wocpm_size_check(struct drm_i915_private *i915)
+{
+	struct intel_guc_wopcm *wopcm = &i915->guc.wopcm;
+	u32 wopcm_base;
+	u32 delta;
+
+	/*
+	 * Check hardware restriction on Gen9
+	 * GuC WOPCM size is at least 4 bytes larger than GuC WOPCM base due
+	 * to hardware limitation on Gen9.
+	 */
+	wopcm_base = wopcm->offset + GEN9_GUC_WOPCM_OFFSET;
+	if (unlikely(wopcm_base > wopcm->size))
+		return -E2BIG;
+
+	delta = wopcm->size - wopcm_base;
+	if (unlikely(delta < GEN9_GUC_WOPCM_DELTA))
+		return -E2BIG;
+
+	return 0;
+}
+
+static inline int guc_wopcm_size_check(struct intel_guc *guc)
+{
+	struct drm_i915_private *i915 = guc_to_i915(guc);
+
+	if (IS_GEN9(i915))
+		return gen9_wocpm_size_check(i915);
+
+	return 0;
+}
+
 /*
- * intel_guc_wopcm_size() - Get the size of GuC WOPCM.
+ * intel_guc_wopcm_init() - Initialize the GuC WOPCM partition.
  * @guc: intel guc.
+ * @guc_fw_size: size of GuC firmware.
+ * @huc_fw_size: size of HuC firmware.
  *
- * Get the platform specific GuC WOPCM size.
+ * This function tries to initialize the WOPCM partition based on HuC firmware
+ * size and the reserved WOPCM memory size.
  *
- * Return: size of the GuC WOPCM.
+ * Return: 0 on success, non-zero error code on failure.
  */
-u32 intel_guc_wopcm_size(struct intel_guc *guc)
+int intel_guc_wopcm_init(struct intel_guc *guc, u32 guc_fw_size,
+			 u32 huc_fw_size)
 {
-	struct drm_i915_private *i915 = guc_to_i915(guc);
+	u32 reserved = guc_reserved_wopcm_size(guc);
+	u32 offset, size, top;
+	int err;
 
-	u32 wopcm_size = GUC_WOPCM_TOP;
+	if (guc->wopcm.valid)
+		return 0;
 
-	/* On BXT, the top of WOPCM is reserved for RC6 context */
-	if (IS_GEN9_LP(i915))
-		wopcm_size -= BXT_GUC_WOPCM_RC6_RESERVED;
+	if (!guc_fw_size)
+		return -EINVAL;
+
+	if (reserved >= WOPCM_DEFAULT_SIZE)
+		return -E2BIG;
+
+	offset = huc_fw_size + WOPCM_RESERVED_SIZE;
+	if (offset >= WOPCM_DEFAULT_SIZE)
+		return -E2BIG;
+
+	/* Hardware requires GuC WOPCM offset needs to be 16K aligned. */
+	offset = ALIGN(offset, WOPCM_OFFSET_ALIGNMENT);
+	if ((offset + reserved) >= WOPCM_DEFAULT_SIZE)
+		return -E2BIG;
+
+	top = WOPCM_DEFAULT_SIZE - offset;
+	size = top - reserved;
+
+	/* GuC WOPCM size must be 4K aligned. */
+	size &= GUC_WOPCM_SIZE_MASK;
+
+	/*
+	 * GuC size needs to be less than or equal to GuC WOPCM size.
+	 * Need extra 8K stack for GuC.
+	 */
+	if ((guc_fw_size + GUC_WOPCM_STACK_RESERVED) > size)
+		return -E2BIG;
+
+	guc->wopcm.offset = offset;
+	guc->wopcm.size = size;
+	guc->wopcm.top = top;
+
+	/* Check platform specific restrictions */
+	err = guc_wopcm_size_check(guc);
+	if (err)
+		return err;
+
+	guc->wopcm.valid = true;
+
+	DRM_DEBUG_DRIVER("GuC WOPCM offset %dKB, size %dKB, top %dKB\n",
+			 offset >> 10, size >> 10, top >> 10);
 
-	return wopcm_size;
+	return 0;
 }
diff --git a/drivers/gpu/drm/i915/intel_guc_wopcm.h b/drivers/gpu/drm/i915/intel_guc_wopcm.h
index 595fb1c..352cf3d 100644
--- a/drivers/gpu/drm/i915/intel_guc_wopcm.h
+++ b/drivers/gpu/drm/i915/intel_guc_wopcm.h
@@ -29,11 +29,41 @@ 
 
 struct intel_guc;
 
-#define   GUC_WOPCM_OFFSET_VALUE	0x80000	/* 512KB */
-/* GuC addresses below GUC_WOPCM_TOP don't map through the GTT */
-#define GUC_WOPCM_TOP			(0x80 << 12)	/* 512KB */
-#define BXT_GUC_WOPCM_RC6_RESERVED	(0x10 << 12)	/* 64KB  */
+/* Default WOPCM size 1MB */
+#define WOPCM_DEFAULT_SIZE		(0x1 << 20)
+/* Reserved WOPCM size 16KB */
+#define WOPCM_RESERVED_SIZE		(0x4000)
+/* GUC WOPCM Offset need to be 16KB aligned */
+#define WOPCM_OFFSET_ALIGNMENT		(0x4000)
+/* 8KB stack reserved for GuC FW*/
+#define GUC_WOPCM_STACK_RESERVED	(0x2000)
+/* 24KB WOPCM reserved for RC6 CTX on BXT */
+#define BXT_WOPCM_RC6_RESERVED		(0x6000)
 
-u32 intel_guc_wopcm_size(struct intel_guc *guc);
+#define GEN9_GUC_WOPCM_DELTA		4
+#define GEN9_GUC_WOPCM_OFFSET		(0x24000)
+
+struct intel_guc_wopcm {
+	u32 offset;
+	u32 size;
+	u32 top;
+	bool valid;
+};
+
+/*
+ * intel_guc_wopcm_init_early() - Early initialization of the GuC WOPCM.
+ * @wopcm: GuC WOPCM.
+ *
+ * Setup the GuC WOPCM top to the top of the overall WOPCM. This will guarantee
+ * that the allocation of the GuC accessible objects won't fall into WOPCM when
+ * GuC partition isn't present.
+ *
+ */
+static inline void intel_guc_wopcm_init_early(struct intel_guc_wopcm *wopcm)
+{
+	wopcm->top = WOPCM_DEFAULT_SIZE;
+}
+
+int intel_guc_wopcm_init(struct intel_guc *guc, u32 guc_size, u32 huc_size);
 
 #endif
diff --git a/drivers/gpu/drm/i915/intel_huc.c b/drivers/gpu/drm/i915/intel_huc.c
index aed9c1c..dc6a6c6 100644
--- a/drivers/gpu/drm/i915/intel_huc.c
+++ b/drivers/gpu/drm/i915/intel_huc.c
@@ -206,7 +206,7 @@  int intel_huc_auth(struct intel_huc *huc)
 		return -ENOEXEC;
 
 	vma = i915_gem_object_ggtt_pin(huc->fw.obj, NULL, 0, 0,
-				PIN_OFFSET_BIAS | GUC_WOPCM_TOP);
+				PIN_OFFSET_BIAS | guc->wopcm.top);
 	if (IS_ERR(vma)) {
 		ret = PTR_ERR(vma);
 		DRM_ERROR("HuC: Failed to pin huc fw object %d\n", ret);
diff --git a/drivers/gpu/drm/i915/intel_uc.c b/drivers/gpu/drm/i915/intel_uc.c
index e9d0568..b5a08d1 100644
--- a/drivers/gpu/drm/i915/intel_uc.c
+++ b/drivers/gpu/drm/i915/intel_uc.c
@@ -263,6 +263,9 @@  void intel_uc_fini_wq(struct drm_i915_private *dev_priv)
 int intel_uc_init(struct drm_i915_private *dev_priv)
 {
 	struct intel_guc *guc = &dev_priv->guc;
+	struct intel_huc *huc = &dev_priv->huc;
+	u32 guc_fw_size = intel_uc_fw_get_size(&guc->fw);
+	u32 huc_fw_size = intel_uc_fw_get_size(&huc->fw);
 	int ret;
 
 	if (!USES_GUC(dev_priv))
@@ -271,6 +274,10 @@  int intel_uc_init(struct drm_i915_private *dev_priv)
 	if (!HAS_GUC(dev_priv))
 		return -ENODEV;
 
+	ret = intel_guc_wopcm_init(guc, guc_fw_size, huc_fw_size);
+	if (ret)
+		return ret;
+
 	ret = intel_guc_init(guc);
 	if (ret)
 		return ret;
@@ -320,9 +327,9 @@  int intel_uc_init_hw(struct drm_i915_private *dev_priv)
 	gen9_reset_guc_interrupts(dev_priv);
 
 	/* init WOPCM */
-	I915_WRITE(GUC_WOPCM_SIZE, intel_guc_wopcm_size(guc));
+	I915_WRITE(GUC_WOPCM_SIZE, guc->wopcm.size);
 	I915_WRITE(DMA_GUC_WOPCM_OFFSET,
-		   GUC_WOPCM_OFFSET_VALUE | HUC_LOADING_AGENT_GUC);
+		   guc->wopcm.offset | HUC_LOADING_AGENT_GUC);
 
 	/* WaEnableuKernelHeaderValidFix:skl */
 	/* WaEnableGuCBootHashCheckNotSet:skl,bxt,kbl */
diff --git a/drivers/gpu/drm/i915/intel_uc_fw.c b/drivers/gpu/drm/i915/intel_uc_fw.c
index 24945cf..791263a 100644
--- a/drivers/gpu/drm/i915/intel_uc_fw.c
+++ b/drivers/gpu/drm/i915/intel_uc_fw.c
@@ -95,9 +95,13 @@  void intel_uc_fw_fetch(struct drm_i915_private *dev_priv,
 	uc_fw->ucode_offset = uc_fw->header_offset + uc_fw->header_size;
 	uc_fw->ucode_size = (css->size_dw - css->header_size_dw) * sizeof(u32);
 
-	/* Header and uCode will be loaded to WOPCM */
+	/*
+	 * Header and uCode will be loaded to WOPCM
+	 * Only check the size against the overall available WOPCM here. Will
+	 * continue to check the size during WOPCM partition calculation.
+	 */
 	size = uc_fw->header_size + uc_fw->ucode_size;
-	if (size > intel_guc_wopcm_size(&dev_priv->guc)) {
+	if (size > WOPCM_DEFAULT_SIZE) {
 		DRM_WARN("%s: Firmware is too large to fit in WOPCM\n",
 			 intel_uc_fw_type_repr(uc_fw->type));
 		err = -E2BIG;
@@ -207,6 +211,7 @@  int intel_uc_fw_upload(struct intel_uc_fw *uc_fw,
 		       int (*xfer)(struct intel_uc_fw *uc_fw,
 				   struct i915_vma *vma))
 {
+	struct drm_i915_private *i915 = to_i915(uc_fw->obj->base.dev);
 	struct i915_vma *vma;
 	int err;
 
@@ -230,7 +235,7 @@  int intel_uc_fw_upload(struct intel_uc_fw *uc_fw,
 	}
 
 	vma = i915_gem_object_ggtt_pin(uc_fw->obj, NULL, 0, 0,
-				       PIN_OFFSET_BIAS | GUC_WOPCM_TOP);
+				       PIN_OFFSET_BIAS | i915->guc.wopcm.top);
 	if (IS_ERR(vma)) {
 		err = PTR_ERR(vma);
 		DRM_DEBUG_DRIVER("%s fw ggtt-pin err=%d\n",
diff --git a/drivers/gpu/drm/i915/intel_uc_fw.h b/drivers/gpu/drm/i915/intel_uc_fw.h
index d5fd460..d00d888 100644
--- a/drivers/gpu/drm/i915/intel_uc_fw.h
+++ b/drivers/gpu/drm/i915/intel_uc_fw.h
@@ -115,6 +115,22 @@  static inline bool intel_uc_fw_is_selected(struct intel_uc_fw *uc_fw)
 	return uc_fw->path != NULL;
 }
 
+/*
+ * intel_uc_fw_get_size() - Get the size of the firmware.
+ * @uc_fw: intel_uc_fw structure.
+ *
+ * Get the size of the firmware that will be placed in WOPCM.
+ *
+ * Return: Zero on invalid firmware status. actual size on success.
+ */
+static inline u32 intel_uc_fw_get_size(struct intel_uc_fw *uc_fw)
+{
+	if (uc_fw->fetch_status != INTEL_UC_FIRMWARE_SUCCESS)
+		return 0;
+
+	return uc_fw->header_size + uc_fw->ucode_size;
+}
+
 void intel_uc_fw_fetch(struct drm_i915_private *dev_priv,
 		       struct intel_uc_fw *uc_fw);
 int intel_uc_fw_upload(struct intel_uc_fw *uc_fw,