Message ID | 1517875362-12755-3-git-send-email-yaodong.li@intel.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
change looks good to me. minor updates suggested with r-b. On 2/6/2018 5:32 AM, Jackie Li wrote: > Hardware may have specific restrictions on GuC WOPCM offset and size. On > Gen9, the value of the GuC WOPCM size register needs to be larger than the > value of GuC WOPCM offset register + a Gen9 specific offset (144KB) for > reserved GuC WOPCM. Fail to enforce such a restriction on GuC WOPCM size > will lead to GuC firmware execution failures. Add below line here? Second restriction is for Gen9 and Gen10 and it is w.r.t. HuC firmware size as per which "GuC WOPCM size - 16K" should be greater than or equal to HuC firmware size. > So we need add code to verify > the GuC WOPCM offset and size to avoid any GuC failures. On the other hand, > with current static GuC WOPCM offset and size values (512KB for both offset > and size), the GuC WOPCM size verification will fail on Gen9 even if it can > be fixed by lowering the GuC WOPCM offset by calculating its value based on > HuC firmware size (which is likely less than 200KB on Gen9), so that we can > have a GuC WOPCM size value which is large enough to pass the GuC WOPCM > size check. > > This patch updates the reserved GuC WOPCM size for RC6 context on Gen9 to > 24KB to strictly align with the Gen9 GuC WOPCM layout. It also adds support > to verify the GuC WOPCM size aganist the Gen9 hardware restrictions. > Meanwhile, it provides a common way to calculate GuC WOPCM offset and size > based on GuC and HuC firmware sizes for all GuC/HuC enabled platforms. > Currently, GuC WOPCM offset is calculated based on HuC firmware size + > reserved WOPCM size while GuC WOPCM size is set to total WOPCM size - GuC > WOPCM offset - reserved 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) > > v8: > - Updated comments and fixed naming issues (Sagar/Joonas) > - Updated commit message to include more description about the hardware > restriction on GuC WOPCM size (Sagar) > > 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> Reviewed-by: Sagar Arun Kamble <sagar.a.kamble@intel.com> > --- > drivers/gpu/drm/i915/i915_gem_context.c | 5 +- > drivers/gpu/drm/i915/intel_guc.c | 5 +- > drivers/gpu/drm/i915/intel_guc.h | 12 ++-- > drivers/gpu/drm/i915/intel_guc_wopcm.c | 116 +++++++++++++++++++++++++++++--- > drivers/gpu/drm/i915/intel_guc_wopcm.h | 66 ++++++++++++++++-- > 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 +++++ > 9 files changed, 213 insertions(+), 31 deletions(-) > > diff --git a/drivers/gpu/drm/i915/i915_gem_context.c b/drivers/gpu/drm/i915/i915_gem_context.c > index 648e753..546404e 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 > + /* > + * 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 d9bc2a9..ecd5da2 100644 > --- a/drivers/gpu/drm/i915/intel_guc.c > +++ b/drivers/gpu/drm/i915/intel_guc.c > @@ -65,6 +65,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_log_init_early(guc); > + intel_guc_wopcm_init_early(&guc->wopcm); > > mutex_init(&guc->send_mutex); > guc->send = intel_guc_send_nop; > @@ -478,7 +479,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. > @@ -499,7 +500,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 50be6de..06f315e 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; > @@ -109,10 +110,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. > */ > @@ -121,7 +122,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_wopcm.c b/drivers/gpu/drm/i915/intel_guc_wopcm.c > index 73be9af..1555e79 100644 > --- a/drivers/gpu/drm/i915/intel_guc_wopcm.c > +++ b/drivers/gpu/drm/i915/intel_guc_wopcm.c > @@ -25,22 +25,116 @@ > #include "intel_guc_wopcm.h" > #include "i915_drv.h" > > -/* > - * intel_guc_wopcm_size() - Get the size of GuC WOPCM. > +static inline u32 guc_reserved_wopcm_size(struct intel_guc *guc) > +{ > + struct drm_i915_private *i915 = guc_to_i915(guc); > + > + if (IS_GEN9_LP(i915)) > + return BXT_GUC_WOPCM_RC6_RESERVED; > + > + return 0; > +} > + > +static inline int gen9_guc_wopcm_size_check(struct drm_i915_private *i915) > +{ > + struct intel_guc_wopcm *wopcm = &i915->guc.wopcm; use variable name as guc_wopcm? > + u32 guc_wopcm_start; > + u32 delta; > + > + /* > + * GuC WOPCM size is at least 4 bytes larger than the offset from WOPCM > + * base (GuC WOPCM offset from WOPCM base + GEN9_GUC_WOPCM_OFFSET) due > + * to hardware limitation on Gen9. > + */ > + guc_wopcm_start = wopcm->offset + GEN9_GUC_WOPCM_OFFSET; > + if (unlikely(guc_wopcm_start > wopcm->size)) > + return -E2BIG; > + > + delta = wopcm->size - guc_wopcm_start; > + if (unlikely(delta < GEN9_GUC_WOPCM_DELTA)) > + return -E2BIG; > + > + return 0; > +} > + > +static inline int guc_wopcm_check_hw_restrictions(struct intel_guc *guc) > +{ > + struct drm_i915_private *i915 = guc_to_i915(guc); > + > + if (IS_GEN9(i915)) > + return gen9_guc_wopcm_size_check(i915); > + > + return 0; > +} > + > +/** > + * intel_guc_wopcm_init() - Initialize the GuC WOPCM.. remove extra "." > * @guc: intel guc. > + * @guc_fw_size: size of GuC firmware. > + * @huc_fw_size: size of HuC firmware. > * > - * Get the platform specific GuC WOPCM size. > + * Calculate the GuC WOPCM offset and size based on GuC and HuC firmware sizes. > + * This function will to set the GuC WOPCM size to the size of maximum WOPCM remove "to" > + * available for GuC. This function will also enforce platform dependent > + * hardware restrictions on GuC WOPCM offset and size. It will fail the GuC > + * WOPCM init if any of these checks were failed, so that the following GuC > + * firmware uploading would be aborted. > * > - * 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 size = GUC_WOPCM_TOP; > + u32 reserved = guc_reserved_wopcm_size(guc); > + u32 offset, size, top; > + int err; > > - /* On BXT, the top of WOPCM is reserved for RC6 context */ > - if (IS_GEN9_LP(i915)) > - size -= BXT_GUC_WOPCM_RC6_RESERVED; > + if (guc->wopcm.valid) > + return 0; > + > + 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 to be 16K aligned. */ > + offset = ALIGN(offset, GUC_WOPCM_OFFSET_ALIGNMENT); > + if ((offset + reserved) >= WOPCM_DEFAULT_SIZE) > + return -E2BIG; > + > + top = WOPCM_DEFAULT_SIZE - offset; > + size = top - reserved; > + > + /* GuC WOPCM size must be multiple of 4K pages */ > + size &= PAGE_MASK; > + > + /* > + * GuC firmware size needs to be less than or equal to the size of the > + * available GuC WOPCM (total available GuC WOPCM size - reserved size). > + * Need extra 8K stack for GuC firmware. > + */ > + reserved = GUC_WOPCM_RESERVED + GUC_WOPCM_STACK_RESERVED; > + if ((guc_fw_size + reserved) > size) > + return -E2BIG; > + > + guc->wopcm.offset = offset; > + guc->wopcm.size = size; > + guc->wopcm.top = top; > + > + /* Check platform specific restrictions */ > + err = guc_wopcm_check_hw_restrictions(guc); > + if (err) > + return err; > + > + guc->wopcm.valid = 1; > + > + DRM_DEBUG_DRIVER("GuC WOPCM offset %dKB, size %dKB, top %dKB\n", > + offset >> 10, size >> 10, top >> 10); > > - return size; > + return 0; > } > diff --git a/drivers/gpu/drm/i915/intel_guc_wopcm.h b/drivers/gpu/drm/i915/intel_guc_wopcm.h > index 53de931..28e4103 100644 > --- a/drivers/gpu/drm/i915/intel_guc_wopcm.h > +++ b/drivers/gpu/drm/i915/intel_guc_wopcm.h > @@ -29,11 +29,67 @@ > > 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) > +/* The initial 16KB WOPCM is reserved. */ > +#define WOPCM_RESERVED_SIZE (0x4000) > > -u32 intel_guc_wopcm_size(struct intel_guc *guc); > +/* GUC WOPCM offset needs to be 16KB aligned. */ > +#define GUC_WOPCM_OFFSET_ALIGNMENT (0x4000) > +/* 16KB reserved at the beginning of GuC WOPCM. */ > +#define GUC_WOPCM_RESERVED (0x4000) > +/* 8KB from GUC_WOPCM_RESERVED is reserved for GuC stack. */ > +#define GUC_WOPCM_STACK_RESERVED (0x2000) > +/* 24KB at the end of GuC WOPCM is reserved for RC6 CTX on BXT. */ > +#define BXT_GUC_WOPCM_RC6_RESERVED (0x6000) > + > +#define GEN9_GUC_WOPCM_DELTA 4 > +/** Only "/*" > + * GuC WOPCM starts at 144KB (GUC_WOPCM_RESERVED + 128KB reserved for GuC > + * firmware loading) from GuC WOPCM offset on BXT. > + */ > +#define GEN9_GUC_WOPCM_OFFSET (0x24000) > + > +/** > + * intel_guc_wopcm - GuC WOPCM related settings. > + * @offset: GuC WOPCM offset from the WOPCM base. > + * @size: size of GuC WOPCM for GuC firmware. > + * @top: start of the non-GuC WOPCM memory. > + * @valid: whether this structure contains valid (1-valid, 0-invalid) info. > + * > + * We simply use this structure to track the GuC use of WOPCM. The layout of > + * WOPCM would be defined by writing to GuC WOPCM offset and size registers as > + * shown below. > + * > + * +-----------+<-- top > + * |###########| > + * +-----------+<-- size (GuC_WOPCM_SIZE register) > + * | GuC WOPCM | > + * +-----------+<-- offset (DMA_GUC_WOPCM_OFFSET register) > + * |###########| > + * +-----------+<-- WOPCM base > + */ > +struct intel_guc_wopcm { > + u32 offset; > + u32 size; > + u32 top; > + u32 valid; > +}; > + > +/** > + * intel_guc_wopcm_init_early() - Early initialization of the GuC WOPCM. > + * @wopcm: GuC WOPCM. Update this name too? > + * > + * 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 1b2831b..2292f31 100644 > --- a/drivers/gpu/drm/i915/intel_uc.c > +++ b/drivers/gpu/drm/i915/intel_uc.c > @@ -283,6 +283,9 @@ void intel_uc_fini_misc(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)) > @@ -291,6 +294,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; > @@ -340,9 +347,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..298d475 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,
On Tue, 06 Feb 2018 07:20:41 +0100, Sagar Arun Kamble <sagar.a.kamble@intel.com> wrote: > change looks good to me. minor updates suggested with r-b. > > > On 2/6/2018 5:32 AM, Jackie Li wrote: >> Hardware may have specific restrictions on GuC WOPCM offset and size. On >> Gen9, the value of the GuC WOPCM size register needs to be larger than >> the >> value of GuC WOPCM offset register + a Gen9 specific offset (144KB) for >> reserved GuC WOPCM. Fail to enforce such a restriction on GuC WOPCM size >> will lead to GuC firmware execution failures. > Add below line here? > > Second restriction is for Gen9 and Gen10 and it is w.r.t. HuC firmware > size as per which "GuC WOPCM size - 16K" should > be greater than or equal to HuC firmware size. >> So we need add code to verify >> the GuC WOPCM offset and size to avoid any GuC failures. On the other >> hand, >> with current static GuC WOPCM offset and size values (512KB for both >> offset >> and size), the GuC WOPCM size verification will fail on Gen9 even if it >> can >> be fixed by lowering the GuC WOPCM offset by calculating its value >> based on >> HuC firmware size (which is likely less than 200KB on Gen9), so that we >> can >> have a GuC WOPCM size value which is large enough to pass the GuC WOPCM >> size check. >> >> This patch updates the reserved GuC WOPCM size for RC6 context on Gen9 >> to >> 24KB to strictly align with the Gen9 GuC WOPCM layout. It also adds >> support >> to verify the GuC WOPCM size aganist the Gen9 hardware restrictions. >> Meanwhile, it provides a common way to calculate GuC WOPCM offset and >> size >> based on GuC and HuC firmware sizes for all GuC/HuC enabled platforms. >> Currently, GuC WOPCM offset is calculated based on HuC firmware size + >> reserved WOPCM size while GuC WOPCM size is set to total WOPCM size - >> GuC >> WOPCM offset - reserved 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) >> >> v8: >> - Updated comments and fixed naming issues (Sagar/Joonas) >> - Updated commit message to include more description about the >> hardware >> restriction on GuC WOPCM size (Sagar) >> >> 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> > > Reviewed-by: Sagar Arun Kamble <sagar.a.kamble@intel.com> >> --- >> drivers/gpu/drm/i915/i915_gem_context.c | 5 +- >> drivers/gpu/drm/i915/intel_guc.c | 5 +- >> drivers/gpu/drm/i915/intel_guc.h | 12 ++-- >> drivers/gpu/drm/i915/intel_guc_wopcm.c | 116 >> +++++++++++++++++++++++++++++--- >> drivers/gpu/drm/i915/intel_guc_wopcm.h | 66 ++++++++++++++++-- >> 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 +++++ >> 9 files changed, 213 insertions(+), 31 deletions(-) >> >> diff --git a/drivers/gpu/drm/i915/i915_gem_context.c >> b/drivers/gpu/drm/i915/i915_gem_context.c >> index 648e753..546404e 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 >> + /* >> + * 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; I know that Joonas was against using extra inline function to read value of "guc.wopcm.top" but maybe we should discuss it again as now we maybe using invalid/unset value since now we are not verifying "guc->wopcm.valid" flag. >> 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 d9bc2a9..ecd5da2 100644 >> --- a/drivers/gpu/drm/i915/intel_guc.c >> +++ b/drivers/gpu/drm/i915/intel_guc.c >> @@ -65,6 +65,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_log_init_early(guc); >> + intel_guc_wopcm_init_early(&guc->wopcm); >> mutex_init(&guc->send_mutex); >> guc->send = intel_guc_send_nop; >> @@ -478,7 +479,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. >> @@ -499,7 +500,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 50be6de..06f315e 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; >> @@ -109,10 +110,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. >> */ >> @@ -121,7 +122,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_wopcm.c >> b/drivers/gpu/drm/i915/intel_guc_wopcm.c >> index 73be9af..1555e79 100644 >> --- a/drivers/gpu/drm/i915/intel_guc_wopcm.c >> +++ b/drivers/gpu/drm/i915/intel_guc_wopcm.c >> @@ -25,22 +25,116 @@ >> #include "intel_guc_wopcm.h" >> #include "i915_drv.h" >> -/* >> - * intel_guc_wopcm_size() - Get the size of GuC WOPCM. >> +static inline u32 guc_reserved_wopcm_size(struct intel_guc *guc) >> +{ >> + struct drm_i915_private *i915 = guc_to_i915(guc); >> + >> + if (IS_GEN9_LP(i915)) >> + return BXT_GUC_WOPCM_RC6_RESERVED; >> + >> + return 0; >> +} >> + >> +static inline int gen9_guc_wopcm_size_check(struct drm_i915_private >> *i915) maybe it would be better to pass "wopcm" instead of "i915" ? >> +{ >> + struct intel_guc_wopcm *wopcm = &i915->guc.wopcm; > use variable name as guc_wopcm? >> + u32 guc_wopcm_start; >> + u32 delta; >> + >> + /* >> + * GuC WOPCM size is at least 4 bytes larger than the offset from >> WOPCM Either use 4B directly below (as you give explanation here) or move that comment near the definition of GEN9_GUC_WOPCM_DELTA. >> + * base (GuC WOPCM offset from WOPCM base + GEN9_GUC_WOPCM_OFFSET) due >> + * to hardware limitation on Gen9. >> + */ >> + guc_wopcm_start = wopcm->offset + GEN9_GUC_WOPCM_OFFSET; >> + if (unlikely(guc_wopcm_start > wopcm->size)) >> + return -E2BIG; >> + >> + delta = wopcm->size - guc_wopcm_start; >> + if (unlikely(delta < GEN9_GUC_WOPCM_DELTA)) >> + return -E2BIG; >> + >> + return 0; >> +} >> + >> +static inline int guc_wopcm_check_hw_restrictions(struct intel_guc >> *guc) >> +{ >> + struct drm_i915_private *i915 = guc_to_i915(guc); >> + >> + if (IS_GEN9(i915)) >> + return gen9_guc_wopcm_size_check(i915); please use function name that matches dispatcher function guc_wopcm_check_hw_restrictions() gen9_guc_wopcm_check_hw_restrictions() or guc_wopcm_size_check() gen9_guc_wopcm_size_check() >> + >> + return 0; >> +} >> + >> +/** >> + * intel_guc_wopcm_init() - Initialize the GuC WOPCM.. > remove extra "." >> * @guc: intel guc. >> + * @guc_fw_size: size of GuC firmware. >> + * @huc_fw_size: size of HuC firmware. >> * >> - * Get the platform specific GuC WOPCM size. >> + * Calculate the GuC WOPCM offset and size based on GuC and HuC >> firmware sizes. >> + * This function will to set the GuC WOPCM size to the size of maximum >> WOPCM > remove "to" >> + * available for GuC. This function will also enforce platform >> dependent >> + * hardware restrictions on GuC WOPCM offset and size. It will fail >> the GuC >> + * WOPCM init if any of these checks were failed, so that the >> following GuC >> + * firmware uploading would be aborted. >> * >> - * 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) Hmm, it looks that all your changes for this function from patch 2/6 are now lost ... >> +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 size = GUC_WOPCM_TOP; >> + u32 reserved = guc_reserved_wopcm_size(guc); >> + u32 offset, size, top; >> + int err; >> - /* On BXT, the top of WOPCM is reserved for RC6 context */ >> - if (IS_GEN9_LP(i915)) >> - size -= BXT_GUC_WOPCM_RC6_RESERVED; >> + if (guc->wopcm.valid) >> + return 0; Is there a scenario when this function will be called more than one? >> + >> + if (!guc_fw_size) >> + return -EINVAL; GEM_BUG_ON ? >> + >> + if (reserved >= WOPCM_DEFAULT_SIZE) >> + return -E2BIG; GEM_BUG_ON ? >> + >> + offset = huc_fw_size + WOPCM_RESERVED_SIZE; What's the difference between guc_reserved_wopcm_size and WOPCM_RESERVED_SIZE >> + if (offset >= WOPCM_DEFAULT_SIZE) >> + return -E2BIG; >> + >> + /* Hardware requires GuC WOPCM offset to be 16K aligned. */ >> + offset = ALIGN(offset, GUC_WOPCM_OFFSET_ALIGNMENT); >> + if ((offset + reserved) >= WOPCM_DEFAULT_SIZE) >> + return -E2BIG; >> + >> + top = WOPCM_DEFAULT_SIZE - offset; >> + size = top - reserved; >> + >> + /* GuC WOPCM size must be multiple of 4K pages */ >> + size &= PAGE_MASK; >> + >> + /* >> + * GuC firmware size needs to be less than or equal to the size of the >> + * available GuC WOPCM (total available GuC WOPCM size - reserved >> size). >> + * Need extra 8K stack for GuC firmware. >> + */ >> + reserved = GUC_WOPCM_RESERVED + GUC_WOPCM_STACK_RESERVED; >> + if ((guc_fw_size + reserved) > size) >> + return -E2BIG; >> + >> + guc->wopcm.offset = offset; >> + guc->wopcm.size = size; >> + guc->wopcm.top = top; >> + >> + /* Check platform specific restrictions */ >> + err = guc_wopcm_check_hw_restrictions(guc); maybe you should check HW restrictions *before* initializing the structure? err = check_hw_restrictions(i915, offset, size, top); >> + if (err) >> + return err; >> + >> + guc->wopcm.valid = 1; >> + >> + DRM_DEBUG_DRIVER("GuC WOPCM offset %dKB, size %dKB, top %dKB\n", >> + offset >> 10, size >> 10, top >> 10); >> - return size; >> + return 0; >> } >> diff --git a/drivers/gpu/drm/i915/intel_guc_wopcm.h >> b/drivers/gpu/drm/i915/intel_guc_wopcm.h >> index 53de931..28e4103 100644 >> --- a/drivers/gpu/drm/i915/intel_guc_wopcm.h >> +++ b/drivers/gpu/drm/i915/intel_guc_wopcm.h >> @@ -29,11 +29,67 @@ >> 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) >> +/* The initial 16KB WOPCM is reserved. */ >> +#define WOPCM_RESERVED_SIZE (0x4000) >> -u32 intel_guc_wopcm_size(struct intel_guc *guc); >> +/* GUC WOPCM offset needs to be 16KB aligned. */ >> +#define GUC_WOPCM_OFFSET_ALIGNMENT (0x4000) >> +/* 16KB reserved at the beginning of GuC WOPCM. */ >> +#define GUC_WOPCM_RESERVED (0x4000) >> +/* 8KB from GUC_WOPCM_RESERVED is reserved for GuC stack. */ >> +#define GUC_WOPCM_STACK_RESERVED (0x2000) >> +/* 24KB at the end of GuC WOPCM is reserved for RC6 CTX on BXT. */ >> +#define BXT_GUC_WOPCM_RC6_RESERVED (0x6000) Please use human readable format like (24 * 1024) >> + >> +#define GEN9_GUC_WOPCM_DELTA 4 >> +/** > Only "/*" >> + * GuC WOPCM starts at 144KB (GUC_WOPCM_RESERVED + 128KB reserved for >> GuC >> + * firmware loading) from GuC WOPCM offset on BXT. >> + */ >> +#define GEN9_GUC_WOPCM_OFFSET (0x24000) maybe it is worth to add some drawings like below that describe all these HW restrictions? also as all these definitions are for private use only in guc_wopcm.c file maybe it should be defined there? >> + >> +/** >> + * intel_guc_wopcm - GuC WOPCM related settings. >> + * @offset: GuC WOPCM offset from the WOPCM base. >> + * @size: size of GuC WOPCM for GuC firmware. >> + * @top: start of the non-GuC WOPCM memory. >> + * @valid: whether this structure contains valid (1-valid, 0-invalid) >> info. >> + * >> + * We simply use this structure to track the GuC use of WOPCM. The >> layout of >> + * WOPCM would be defined by writing to GuC WOPCM offset and size >> registers as >> + * shown below. >> + * >> + * +-----------+<-- top >> + * |###########| >> + * +-----------+<-- size (GuC_WOPCM_SIZE register) s/GuC_WOPCM_SIZE/GUC_WOPCM_SIZE >> + * | GuC WOPCM | >> + * +-----------+<-- offset (DMA_GUC_WOPCM_OFFSET register) >> + * |###########| >> + * +-----------+<-- WOPCM base >> + */ >> +struct intel_guc_wopcm { >> + u32 offset; >> + u32 size; >> + u32 top; >> + u32 valid; >> +}; >> + >> +/** >> + * intel_guc_wopcm_init_early() - Early initialization of the GuC >> WOPCM. >> + * @wopcm: GuC WOPCM. > Update this name too? >> + * >> + * 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) in other functions you use "guc" as first parameter, please be consistent. >> +{ >> + 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 1b2831b..2292f31 100644 >> --- a/drivers/gpu/drm/i915/intel_uc.c >> +++ b/drivers/gpu/drm/i915/intel_uc.c >> @@ -283,6 +283,9 @@ void intel_uc_fini_misc(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)) >> @@ -291,6 +294,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; >> @@ -340,9 +347,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..298d475 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,
On 02/06/2018 02:25 PM, Michal Wajdeczko wrote: > >>> 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 >>> + /* >>> + * 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; > > I know that Joonas was against using extra inline function to read > value of "guc.wopcm.top" but maybe we should discuss it again as > now we maybe using invalid/unset value since now we are not verifying > "guc->wopcm.valid" flag. > It should be fine in this case since we have early inited the value to the worst case (using the size of all WOPCM). we could not use valid here since uc_init has been called at this point. >>> >>> +static inline int gen9_guc_wopcm_size_check(struct drm_i915_private >>> *i915) > > maybe it would be better to pass "wopcm" instead of "i915" ? > hmm, I think it's better to have an unified parameter list for all the check functions. and it the same since we will have to get wopcm from i915 anyways. >>> +{ >>> + struct intel_guc_wopcm *wopcm = &i915->guc.wopcm; >> use variable name as guc_wopcm? >>> + u32 guc_wopcm_start; >>> + u32 delta; >>> + >>> + /* >>> + * GuC WOPCM size is at least 4 bytes larger than the offset >>> from WOPCM > > Either use 4B directly below (as you give explanation here) or move that > comment near the definition of GEN9_GUC_WOPCM_DELTA. > >>> + * base (GuC WOPCM offset from WOPCM base + >>> GEN9_GUC_WOPCM_OFFSET) due >>> + * to hardware limitation on Gen9. >>> + */ >>> + guc_wopcm_start = wopcm->offset + GEN9_GUC_WOPCM_OFFSET; >>> + if (unlikely(guc_wopcm_start > wopcm->size)) >>> + return -E2BIG; >>> + >>> + delta = wopcm->size - guc_wopcm_start; >>> + if (unlikely(delta < GEN9_GUC_WOPCM_DELTA)) >>> + return -E2BIG; >>> + >>> + return 0; >>> +} >>> + >>> +static inline int guc_wopcm_check_hw_restrictions(struct intel_guc >>> *guc) >>> +{ >>> + struct drm_i915_private *i915 = guc_to_i915(guc); >>> + >>> + if (IS_GEN9(i915)) >>> + return gen9_guc_wopcm_size_check(i915); > > please use function name that matches dispatcher function > > guc_wopcm_check_hw_restrictions() > gen9_guc_wopcm_check_hw_restrictions() > > or > > guc_wopcm_size_check() > gen9_guc_wopcm_size_check() > >>> + >>> + return 0; >>> +} >>> + >>> +/** >>> + * intel_guc_wopcm_init() - Initialize the GuC WOPCM.. >> remove extra "." >>> * @guc: intel guc. >>> + * @guc_fw_size: size of GuC firmware. >>> + * @huc_fw_size: size of HuC firmware. >>> * >>> - * Get the platform specific GuC WOPCM size. >>> + * Calculate the GuC WOPCM offset and size based on GuC and HuC >>> firmware sizes. >>> + * This function will to set the GuC WOPCM size to the size of >>> maximum WOPCM >> remove "to" >>> + * available for GuC. This function will also enforce platform >>> dependent >>> + * hardware restrictions on GuC WOPCM offset and size. It will fail >>> the GuC >>> + * WOPCM init if any of these checks were failed, so that the >>> following GuC >>> + * firmware uploading would be aborted. >>> * >>> - * 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) > > Hmm, it looks that all your changes for this function from patch 2/6 > are now lost ... > patch 1/6 & 2/6 are only for some code movings. but have to make it clean. but I do not need this func anymore:o) >>> +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 size = GUC_WOPCM_TOP; >>> + u32 reserved = guc_reserved_wopcm_size(guc); >>> + u32 offset, size, top; >>> + int err; >>> - /* On BXT, the top of WOPCM is reserved for RC6 context */ >>> - if (IS_GEN9_LP(i915)) >>> - size -= BXT_GUC_WOPCM_RC6_RESERVED; >>> + if (guc->wopcm.valid) >>> + return 0; > > Is there a scenario when this function will be called more than one? You're right. we need not need such a check anymore. > >>> + >>> + if (!guc_fw_size) >>> + return -EINVAL; > > GEM_BUG_ON ? > >>> + >>> + if (reserved >= WOPCM_DEFAULT_SIZE) >>> + return -E2BIG; > > GEM_BUG_ON ? Will give the control back to uc_init.? > >>> + >>> + offset = huc_fw_size + WOPCM_RESERVED_SIZE; > > What's the difference between guc_reserved_wopcm_size and > WOPCM_RESERVED_SIZE > WOPCM_RESERVED_SIZE is the reserved size in Non-GuC WOPCM. >>> + guc->wopcm.offset = offset; >>> + guc->wopcm.size = size; >>> + guc->wopcm.top = top; >>> + >>> + /* Check platform specific restrictions */ >>> + err = guc_wopcm_check_hw_restrictions(guc); > > maybe you should check HW restrictions *before* initializing the > structure? > > err = check_hw_restrictions(i915, offset, size, top); Actually, I was struggling on this a bit, but it's clearer to have to valid bit in this struct instead of only checking offset/size/top. And now that we have valid bit it would be better to init the other fields and using less parameters for this function? Regards, -Jackie
On Wed, 07 Feb 2018 05:51:56 +0100, Yaodong Li <yaodong.li@intel.com> wrote: > > > On 02/06/2018 02:25 PM, Michal Wajdeczko wrote: >> >>>> 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 >>>> + /* >>>> + * 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; >> >> I know that Joonas was against using extra inline function to read >> value of "guc.wopcm.top" but maybe we should discuss it again as >> now we maybe using invalid/unset value since now we are not verifying >> "guc->wopcm.valid" flag. >> > It should be fine in this case since we have early inited the value to > the worst > case (using the size of all WOPCM). we could not use valid here since > uc_init > has been called at this point. >>>> >>>> +static inline int gen9_guc_wopcm_size_check(struct drm_i915_private >>>> *i915) >> >> maybe it would be better to pass "wopcm" instead of "i915" ? >> > hmm, I think it's better to have an unified parameter list for all the > check functions. > and it the same since we will have to get wopcm from i915 anyways. but you can still access i915 from wopcm using container_of trick. >>>> +{ >>>> + struct intel_guc_wopcm *wopcm = &i915->guc.wopcm; >>> use variable name as guc_wopcm? >>>> + u32 guc_wopcm_start; >>>> + u32 delta; >>>> + >>>> + /* >>>> + * GuC WOPCM size is at least 4 bytes larger than the offset >>>> from WOPCM >> >> Either use 4B directly below (as you give explanation here) or move that >> comment near the definition of GEN9_GUC_WOPCM_DELTA. >> >>>> + * base (GuC WOPCM offset from WOPCM base + >>>> GEN9_GUC_WOPCM_OFFSET) due >>>> + * to hardware limitation on Gen9. >>>> + */ >>>> + guc_wopcm_start = wopcm->offset + GEN9_GUC_WOPCM_OFFSET; >>>> + if (unlikely(guc_wopcm_start > wopcm->size)) >>>> + return -E2BIG; >>>> + >>>> + delta = wopcm->size - guc_wopcm_start; >>>> + if (unlikely(delta < GEN9_GUC_WOPCM_DELTA)) >>>> + return -E2BIG; >>>> + >>>> + return 0; >>>> +} >>>> + >>>> +static inline int guc_wopcm_check_hw_restrictions(struct intel_guc >>>> *guc) >>>> +{ >>>> + struct drm_i915_private *i915 = guc_to_i915(guc); >>>> + >>>> + if (IS_GEN9(i915)) >>>> + return gen9_guc_wopcm_size_check(i915); >> >> please use function name that matches dispatcher function >> >> guc_wopcm_check_hw_restrictions() >> gen9_guc_wopcm_check_hw_restrictions() >> >> or >> >> guc_wopcm_size_check() >> gen9_guc_wopcm_size_check() >> >>>> + >>>> + return 0; >>>> +} >>>> + >>>> +/** >>>> + * intel_guc_wopcm_init() - Initialize the GuC WOPCM.. >>> remove extra "." >>>> * @guc: intel guc. >>>> + * @guc_fw_size: size of GuC firmware. >>>> + * @huc_fw_size: size of HuC firmware. >>>> * >>>> - * Get the platform specific GuC WOPCM size. >>>> + * Calculate the GuC WOPCM offset and size based on GuC and HuC >>>> firmware sizes. >>>> + * This function will to set the GuC WOPCM size to the size of >>>> maximum WOPCM >>> remove "to" >>>> + * available for GuC. This function will also enforce platform >>>> dependent >>>> + * hardware restrictions on GuC WOPCM offset and size. It will fail >>>> the GuC >>>> + * WOPCM init if any of these checks were failed, so that the >>>> following GuC >>>> + * firmware uploading would be aborted. >>>> * >>>> - * 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) >> >> Hmm, it looks that all your changes for this function from patch 2/6 >> are now lost ... >> > patch 1/6 & 2/6 are only for some code movings. but have to make it > clean. > but I do not need this func anymore:o) so maybe part of these code movement was unnecessary, and affected code can be replaced directly in this patch ? >>>> +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 size = GUC_WOPCM_TOP; >>>> + u32 reserved = guc_reserved_wopcm_size(guc); >>>> + u32 offset, size, top; >>>> + int err; >>>> - /* On BXT, the top of WOPCM is reserved for RC6 context */ >>>> - if (IS_GEN9_LP(i915)) >>>> - size -= BXT_GUC_WOPCM_RC6_RESERVED; >>>> + if (guc->wopcm.valid) >>>> + return 0; >> >> Is there a scenario when this function will be called more than one? > You're right. we need not need such a check anymore. >> >>>> + >>>> + if (!guc_fw_size) >>>> + return -EINVAL; >> >> GEM_BUG_ON ? >> >>>> + >>>> + if (reserved >= WOPCM_DEFAULT_SIZE) >>>> + return -E2BIG; >> >> GEM_BUG_ON ? > Will give the control back to uc_init.? Why? Note that we control what guc_reserved_wopcm_size() will return so this check is just for us, we should never fail here. >> >>>> + >>>> + offset = huc_fw_size + WOPCM_RESERVED_SIZE; >> >> What's the difference between guc_reserved_wopcm_size and >> WOPCM_RESERVED_SIZE >> > WOPCM_RESERVED_SIZE is the reserved size in Non-GuC WOPCM. >>>> + guc->wopcm.offset = offset; >>>> + guc->wopcm.size = size; >>>> + guc->wopcm.top = top; >>>> + >>>> + /* Check platform specific restrictions */ >>>> + err = guc_wopcm_check_hw_restrictions(guc); >> >> maybe you should check HW restrictions *before* initializing the >> structure? >> >> err = check_hw_restrictions(i915, offset, size, top); > Actually, I was struggling on this a bit, but it's clearer to have to > valid bit in this > struct instead of only checking offset/size/top. And now that we have > valid bit But if check_hw_restrictions() fails we will return error and we should never use this struct, so this 'valid' bit now seems more redundant. > it would be better to init the other fields and using less parameters > for this function? If I recall correctly x86-64 can pass 6 function parameters in registers. Michal > > Regards, > -Jackie >
On 02/07/2018 09:24 AM, Michal Wajdeczko wrote: int guc_wopcm_check_huc_fw_size(struct guc_wopcm *wopcm, u32 huc_size) >>> >> patch 1/6 & 2/6 are only for some code movings. but have to make it >> clean. >> but I do not need this func anymore:o) > > so maybe part of these code movement was unnecessary, and affected > code can be replaced directly in this patch ? > That's how I did it before!:-) but I learned my lesson that I've to keep every change/patch clear enough or readers will get confused;-) Actually, I was struggling on this a bit, but it's clearer to have to valid bit in this >> struct instead of only checking offset/size/top. And now that we have >> valid bit > > But if check_hw_restrictions() fails we will return error and we should > never use this struct, so this 'valid' bit now seems more redundant. > In current code, we do verify the ggtt offset against wopcm top in our current code which means current code won't trust the fact that ggtt offset would never be used after uc/guc init failed. This is the reason for this valid bit - I won't assume the ggtt_offset would never be called even if the uc/guc_init returned failure either, since it would be weird if we don't check the valid bit in guc_ggtt_offset() but still verify the offset against the wopcm top. Regards, -Jackie
diff --git a/drivers/gpu/drm/i915/i915_gem_context.c b/drivers/gpu/drm/i915/i915_gem_context.c index 648e753..546404e 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 + /* + * 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 d9bc2a9..ecd5da2 100644 --- a/drivers/gpu/drm/i915/intel_guc.c +++ b/drivers/gpu/drm/i915/intel_guc.c @@ -65,6 +65,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_log_init_early(guc); + intel_guc_wopcm_init_early(&guc->wopcm); mutex_init(&guc->send_mutex); guc->send = intel_guc_send_nop; @@ -478,7 +479,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. @@ -499,7 +500,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 50be6de..06f315e 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; @@ -109,10 +110,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. */ @@ -121,7 +122,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_wopcm.c b/drivers/gpu/drm/i915/intel_guc_wopcm.c index 73be9af..1555e79 100644 --- a/drivers/gpu/drm/i915/intel_guc_wopcm.c +++ b/drivers/gpu/drm/i915/intel_guc_wopcm.c @@ -25,22 +25,116 @@ #include "intel_guc_wopcm.h" #include "i915_drv.h" -/* - * intel_guc_wopcm_size() - Get the size of GuC WOPCM. +static inline u32 guc_reserved_wopcm_size(struct intel_guc *guc) +{ + struct drm_i915_private *i915 = guc_to_i915(guc); + + if (IS_GEN9_LP(i915)) + return BXT_GUC_WOPCM_RC6_RESERVED; + + return 0; +} + +static inline int gen9_guc_wopcm_size_check(struct drm_i915_private *i915) +{ + struct intel_guc_wopcm *wopcm = &i915->guc.wopcm; + u32 guc_wopcm_start; + u32 delta; + + /* + * GuC WOPCM size is at least 4 bytes larger than the offset from WOPCM + * base (GuC WOPCM offset from WOPCM base + GEN9_GUC_WOPCM_OFFSET) due + * to hardware limitation on Gen9. + */ + guc_wopcm_start = wopcm->offset + GEN9_GUC_WOPCM_OFFSET; + if (unlikely(guc_wopcm_start > wopcm->size)) + return -E2BIG; + + delta = wopcm->size - guc_wopcm_start; + if (unlikely(delta < GEN9_GUC_WOPCM_DELTA)) + return -E2BIG; + + return 0; +} + +static inline int guc_wopcm_check_hw_restrictions(struct intel_guc *guc) +{ + struct drm_i915_private *i915 = guc_to_i915(guc); + + if (IS_GEN9(i915)) + return gen9_guc_wopcm_size_check(i915); + + return 0; +} + +/** + * intel_guc_wopcm_init() - Initialize the GuC WOPCM.. * @guc: intel guc. + * @guc_fw_size: size of GuC firmware. + * @huc_fw_size: size of HuC firmware. * - * Get the platform specific GuC WOPCM size. + * Calculate the GuC WOPCM offset and size based on GuC and HuC firmware sizes. + * This function will to set the GuC WOPCM size to the size of maximum WOPCM + * available for GuC. This function will also enforce platform dependent + * hardware restrictions on GuC WOPCM offset and size. It will fail the GuC + * WOPCM init if any of these checks were failed, so that the following GuC + * firmware uploading would be aborted. * - * 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 size = GUC_WOPCM_TOP; + u32 reserved = guc_reserved_wopcm_size(guc); + u32 offset, size, top; + int err; - /* On BXT, the top of WOPCM is reserved for RC6 context */ - if (IS_GEN9_LP(i915)) - size -= BXT_GUC_WOPCM_RC6_RESERVED; + if (guc->wopcm.valid) + return 0; + + 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 to be 16K aligned. */ + offset = ALIGN(offset, GUC_WOPCM_OFFSET_ALIGNMENT); + if ((offset + reserved) >= WOPCM_DEFAULT_SIZE) + return -E2BIG; + + top = WOPCM_DEFAULT_SIZE - offset; + size = top - reserved; + + /* GuC WOPCM size must be multiple of 4K pages */ + size &= PAGE_MASK; + + /* + * GuC firmware size needs to be less than or equal to the size of the + * available GuC WOPCM (total available GuC WOPCM size - reserved size). + * Need extra 8K stack for GuC firmware. + */ + reserved = GUC_WOPCM_RESERVED + GUC_WOPCM_STACK_RESERVED; + if ((guc_fw_size + reserved) > size) + return -E2BIG; + + guc->wopcm.offset = offset; + guc->wopcm.size = size; + guc->wopcm.top = top; + + /* Check platform specific restrictions */ + err = guc_wopcm_check_hw_restrictions(guc); + if (err) + return err; + + guc->wopcm.valid = 1; + + DRM_DEBUG_DRIVER("GuC WOPCM offset %dKB, size %dKB, top %dKB\n", + offset >> 10, size >> 10, top >> 10); - return size; + return 0; } diff --git a/drivers/gpu/drm/i915/intel_guc_wopcm.h b/drivers/gpu/drm/i915/intel_guc_wopcm.h index 53de931..28e4103 100644 --- a/drivers/gpu/drm/i915/intel_guc_wopcm.h +++ b/drivers/gpu/drm/i915/intel_guc_wopcm.h @@ -29,11 +29,67 @@ 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) +/* The initial 16KB WOPCM is reserved. */ +#define WOPCM_RESERVED_SIZE (0x4000) -u32 intel_guc_wopcm_size(struct intel_guc *guc); +/* GUC WOPCM offset needs to be 16KB aligned. */ +#define GUC_WOPCM_OFFSET_ALIGNMENT (0x4000) +/* 16KB reserved at the beginning of GuC WOPCM. */ +#define GUC_WOPCM_RESERVED (0x4000) +/* 8KB from GUC_WOPCM_RESERVED is reserved for GuC stack. */ +#define GUC_WOPCM_STACK_RESERVED (0x2000) +/* 24KB at the end of GuC WOPCM is reserved for RC6 CTX on BXT. */ +#define BXT_GUC_WOPCM_RC6_RESERVED (0x6000) + +#define GEN9_GUC_WOPCM_DELTA 4 +/** + * GuC WOPCM starts at 144KB (GUC_WOPCM_RESERVED + 128KB reserved for GuC + * firmware loading) from GuC WOPCM offset on BXT. + */ +#define GEN9_GUC_WOPCM_OFFSET (0x24000) + +/** + * intel_guc_wopcm - GuC WOPCM related settings. + * @offset: GuC WOPCM offset from the WOPCM base. + * @size: size of GuC WOPCM for GuC firmware. + * @top: start of the non-GuC WOPCM memory. + * @valid: whether this structure contains valid (1-valid, 0-invalid) info. + * + * We simply use this structure to track the GuC use of WOPCM. The layout of + * WOPCM would be defined by writing to GuC WOPCM offset and size registers as + * shown below. + * + * +-----------+<-- top + * |###########| + * +-----------+<-- size (GuC_WOPCM_SIZE register) + * | GuC WOPCM | + * +-----------+<-- offset (DMA_GUC_WOPCM_OFFSET register) + * |###########| + * +-----------+<-- WOPCM base + */ +struct intel_guc_wopcm { + u32 offset; + u32 size; + u32 top; + u32 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 1b2831b..2292f31 100644 --- a/drivers/gpu/drm/i915/intel_uc.c +++ b/drivers/gpu/drm/i915/intel_uc.c @@ -283,6 +283,9 @@ void intel_uc_fini_misc(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)) @@ -291,6 +294,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; @@ -340,9 +347,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..298d475 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,
Hardware may have specific restrictions on GuC WOPCM offset and size. On Gen9, the value of the GuC WOPCM size register needs to be larger than the value of GuC WOPCM offset register + a Gen9 specific offset (144KB) for reserved GuC WOPCM. Fail to enforce such a restriction on GuC WOPCM size will lead to GuC firmware execution failures. So we need add code to verify the GuC WOPCM offset and size to avoid any GuC failures. On the other hand, with current static GuC WOPCM offset and size values (512KB for both offset and size), the GuC WOPCM size verification will fail on Gen9 even if it can be fixed by lowering the GuC WOPCM offset by calculating its value based on HuC firmware size (which is likely less than 200KB on Gen9), so that we can have a GuC WOPCM size value which is large enough to pass the GuC WOPCM size check. This patch updates the reserved GuC WOPCM size for RC6 context on Gen9 to 24KB to strictly align with the Gen9 GuC WOPCM layout. It also adds support to verify the GuC WOPCM size aganist the Gen9 hardware restrictions. Meanwhile, it provides a common way to calculate GuC WOPCM offset and size based on GuC and HuC firmware sizes for all GuC/HuC enabled platforms. Currently, GuC WOPCM offset is calculated based on HuC firmware size + reserved WOPCM size while GuC WOPCM size is set to total WOPCM size - GuC WOPCM offset - reserved 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) v8: - Updated comments and fixed naming issues (Sagar/Joonas) - Updated commit message to include more description about the hardware restriction on GuC WOPCM size (Sagar) 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 | 5 +- drivers/gpu/drm/i915/intel_guc.c | 5 +- drivers/gpu/drm/i915/intel_guc.h | 12 ++-- drivers/gpu/drm/i915/intel_guc_wopcm.c | 116 +++++++++++++++++++++++++++++--- drivers/gpu/drm/i915/intel_guc_wopcm.h | 66 ++++++++++++++++-- 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 +++++ 9 files changed, 213 insertions(+), 31 deletions(-)