From patchwork Sat Nov 4 00:01:09 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jackie Li X-Patchwork-Id: 10041373 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id 15CC6602D8 for ; Sat, 4 Nov 2017 00:03:21 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 05D922984C for ; Sat, 4 Nov 2017 00:03:21 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id EE91829A11; Sat, 4 Nov 2017 00:03:20 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-4.2 required=2.0 tests=BAYES_00, RCVD_IN_DNSWL_MED autolearn=ham version=3.3.1 Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) (using TLSv1.2 with cipher DHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.wl.linuxfoundation.org (Postfix) with ESMTPS id E3BDB2984C for ; Sat, 4 Nov 2017 00:03:19 +0000 (UTC) Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id 57E926EB41; Sat, 4 Nov 2017 00:03:18 +0000 (UTC) X-Original-To: intel-gfx@lists.freedesktop.org Delivered-To: intel-gfx@lists.freedesktop.org Received: from mga07.intel.com (mga07.intel.com [134.134.136.100]) by gabe.freedesktop.org (Postfix) with ESMTPS id B85C76EB41 for ; Sat, 4 Nov 2017 00:03:15 +0000 (UTC) Received: from fmsmga005.fm.intel.com ([10.253.24.32]) by orsmga105.jf.intel.com with ESMTP; 03 Nov 2017 17:03:15 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.44,339,1505804400"; d="scan'208";a="171312104" Received: from yli84-z170x-ud5.fm.intel.com ([10.19.83.14]) by fmsmga005.fm.intel.com with ESMTP; 03 Nov 2017 17:03:14 -0700 From: Jackie Li To: intel-gfx@lists.freedesktop.org Date: Fri, 3 Nov 2017 17:01:09 -0700 Message-Id: <1509753670-27369-1-git-send-email-yaodong.li@intel.com> X-Mailer: git-send-email 2.7.4 Cc: Sujaritha Sundaresan Subject: [Intel-gfx] [PATCH 1/2] drm/i915: implemented dynamic WOPCM partition. X-BeenThere: intel-gfx@lists.freedesktop.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: Intel graphics driver community testing & development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: intel-gfx-bounces@lists.freedesktop.org Sender: "Intel-gfx" X-Virus-Scanned: ClamAV using ClamSMTP Static WOPCM partitioning would lead to GuC loading failure if the GuC/HuC firmware size exceeded current static 512KB partition boundary. This patch enabled the dynamical calculation of the WOPCM aperture used by GuC/HuC firmware. GuC WOPCM offset was set to HuC size + reserved WOPCM size. GuC WOPCM size was set to total WOPCM size - GuC WOPCM offset - RC6CTX size. Signed-off-by: Jackie Li Cc: Michal Wajdeczko Cc: Sagar Arun Kamble Cc: Sujaritha Sundaresan Reviewed-by: Daniele Ceraolo Spurio Reviewed-by: John Spotswood Reviewed-by: Oscar Mateo --- drivers/gpu/drm/i915/i915_drv.c | 15 ++++ drivers/gpu/drm/i915/i915_drv.h | 13 ++++ drivers/gpu/drm/i915/i915_gem_context.c | 4 +- drivers/gpu/drm/i915/i915_guc_reg.h | 18 ++++- drivers/gpu/drm/i915/intel_guc.c | 46 ++++++++++-- drivers/gpu/drm/i915/intel_guc.h | 18 +---- drivers/gpu/drm/i915/intel_huc.c | 3 +- drivers/gpu/drm/i915/intel_uc.c | 128 +++++++++++++++++++++++++++++++- drivers/gpu/drm/i915/intel_uc_fw.c | 12 ++- 9 files changed, 223 insertions(+), 34 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index e7e9e06..19509fd 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -623,6 +623,15 @@ static void i915_gem_fini(struct drm_i915_private *dev_priv) WARN_ON(!list_empty(&dev_priv->contexts.list)); } +static void i915_wopcm_init(struct drm_i915_private *dev_priv) +{ + struct intel_wopcm_info *wopcm = &dev_priv->wopcm; + + wopcm->size = WOPCM_DEFAULT_SIZE; + + DRM_DEBUG_DRIVER("WOPCM size: %dKB\n", wopcm->size >> 10); +} + static int i915_load_modeset_init(struct drm_device *dev) { struct drm_i915_private *dev_priv = to_i915(dev); @@ -670,6 +679,12 @@ static int i915_load_modeset_init(struct drm_device *dev) if (ret) goto cleanup_irq; + /* + * Get the wopcm memory info. + * NOTE: this need to be called before init FW. + */ + i915_wopcm_init(dev_priv); + intel_uc_init_fw(dev_priv); ret = i915_gem_init(dev_priv); diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 72bb5b5..61cd290 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -2235,6 +2235,16 @@ struct intel_cdclk_state { u8 voltage_level; }; +struct intel_wopcm_info { + u32 size; +}; + +struct intel_wopcm_partition { + u32 guc_wopcm_offset; + u32 guc_wopcm_size; + u32 guc_wopcm_top; +}; + struct drm_i915_private { struct drm_device drm; @@ -2258,6 +2268,9 @@ struct drm_i915_private { struct intel_huc huc; struct intel_guc guc; + struct intel_wopcm_info wopcm; + struct intel_wopcm_partition wopcm_partition; + struct intel_csr csr; struct intel_gmbus gmbus[GMBUS_NUM_PINS]; diff --git a/drivers/gpu/drm/i915/i915_gem_context.c b/drivers/gpu/drm/i915/i915_gem_context.c index 10affb3..7347fd7 100644 --- a/drivers/gpu/drm/i915/i915_gem_context.c +++ b/drivers/gpu/drm/i915/i915_gem_context.c @@ -312,12 +312,12 @@ __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 (HAS_GUC(dev_priv) && i915_modparams.enable_guc_loading) - ctx->ggtt_offset_bias = GUC_WOPCM_TOP; + ctx->ggtt_offset_bias = intel_guc_wopcm_top(dev_priv); else ctx->ggtt_offset_bias = I915_GTT_PAGE_SIZE; diff --git a/drivers/gpu/drm/i915/i915_guc_reg.h b/drivers/gpu/drm/i915/i915_guc_reg.h index 35cf991..d309884 100644 --- a/drivers/gpu/drm/i915/i915_guc_reg.h +++ b/drivers/gpu/drm/i915/i915_guc_reg.h @@ -67,17 +67,27 @@ #define DMA_GUC_WOPCM_OFFSET _MMIO(0xc340) #define HUC_LOADING_AGENT_VCR (0<<1) #define HUC_LOADING_AGENT_GUC (1<<1) -#define GUC_WOPCM_OFFSET_VALUE 0x80000 /* 512KB */ #define GUC_MAX_IDLE_COUNT _MMIO(0xC3E4) #define HUC_STATUS2 _MMIO(0xD3B0) #define HUC_FW_VERIFIED (1<<7) /* Defines WOPCM space available to GuC firmware */ +/* 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) + +#define GEN9_GUC_WOPCM_DELTA 4 +#define GEN9_GUC_WOPCM_OFFSET (0x24000) + #define GUC_WOPCM_SIZE _MMIO(0xc050) -/* 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 */ /* 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.c b/drivers/gpu/drm/i915/intel_guc.c index 9678630..0efcfb4 100644 --- a/drivers/gpu/drm/i915/intel_guc.c +++ b/drivers/gpu/drm/i915/intel_guc.c @@ -337,7 +337,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. @@ -358,7 +358,8 @@ 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 | + intel_guc_wopcm_top(dev_priv)); if (ret) { vma = ERR_PTR(ret); goto err; @@ -373,11 +374,42 @@ struct i915_vma *intel_guc_allocate_vma(struct intel_guc *guc, u32 size) u32 intel_guc_wopcm_size(struct drm_i915_private *dev_priv) { - u32 wopcm_size = GUC_WOPCM_TOP; + struct intel_wopcm_partition *wp = &dev_priv->wopcm_partition; - /* On BXT, the top of WOPCM is reserved for RC6 context */ - if (IS_GEN9_LP(dev_priv)) - wopcm_size -= BXT_GUC_WOPCM_RC6_RESERVED; + GEM_BUG_ON(!wp->guc_wopcm_size); - return wopcm_size; + return wp->guc_wopcm_size; +} + +u32 intel_guc_wopcm_top(struct drm_i915_private *dev_priv) +{ + struct intel_wopcm_partition *wp = &dev_priv->wopcm_partition; + + GEM_BUG_ON(!dev_priv->wopcm.size); + + return wp->guc_wopcm_top ? wp->guc_wopcm_top : dev_priv->wopcm.size; +} + +u32 intel_guc_wopcm_offset(struct drm_i915_private *dev_priv) +{ + struct intel_wopcm_partition *wp = &dev_priv->wopcm_partition; + + GEM_BUG_ON(!wp->guc_wopcm_size); + + return wp->guc_wopcm_offset; +} + +/* + * GuC does not allow any gfx GGTT address that falls into range [0, 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. + */ +u32 guc_ggtt_offset(struct i915_vma *vma) +{ + struct drm_i915_private *dev_priv = vma->vm->i915; + u32 offset = i915_ggtt_offset(vma); + + GEM_BUG_ON(offset < intel_guc_wopcm_top(dev_priv)); + GEM_BUG_ON(range_overflows_t(u64, offset, vma->size, GUC_GGTT_TOP)); + return offset; } diff --git a/drivers/gpu/drm/i915/intel_guc.h b/drivers/gpu/drm/i915/intel_guc.h index 607e025..1493de0 100644 --- a/drivers/gpu/drm/i915/intel_guc.h +++ b/drivers/gpu/drm/i915/intel_guc.h @@ -100,21 +100,6 @@ static inline void intel_guc_notify(struct intel_guc *guc) guc->notify(guc); } -/* - * 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. - */ -static inline u32 guc_ggtt_offset(struct i915_vma *vma) -{ - u32 offset = i915_ggtt_offset(vma); - - GEM_BUG_ON(offset < GUC_WOPCM_TOP); - GEM_BUG_ON(range_overflows_t(u64, offset, vma->size, GUC_GGTT_TOP)); - - return offset; -} void intel_guc_init_early(struct intel_guc *guc); void intel_guc_init_send_regs(struct intel_guc *guc); @@ -127,5 +112,8 @@ int intel_guc_suspend(struct drm_i915_private *dev_priv); int intel_guc_resume(struct drm_i915_private *dev_priv); struct i915_vma *intel_guc_allocate_vma(struct intel_guc *guc, u32 size); u32 intel_guc_wopcm_size(struct drm_i915_private *dev_priv); +u32 intel_guc_wopcm_top(struct drm_i915_private *dev_priv); +u32 intel_guc_wopcm_offset(struct drm_i915_private *dev_priv); +u32 guc_ggtt_offset(struct i915_vma *vma); #endif diff --git a/drivers/gpu/drm/i915/intel_huc.c b/drivers/gpu/drm/i915/intel_huc.c index 98d1725..a985aa5 100644 --- a/drivers/gpu/drm/i915/intel_huc.c +++ b/drivers/gpu/drm/i915/intel_huc.c @@ -202,7 +202,8 @@ void intel_huc_auth(struct intel_huc *huc) return; vma = i915_gem_object_ggtt_pin(huc->fw.obj, NULL, 0, 0, - PIN_OFFSET_BIAS | GUC_WOPCM_TOP); + PIN_OFFSET_BIAS | + intel_guc_wopcm_top(i915)); if (IS_ERR(vma)) { DRM_ERROR("failed to pin huc fw object %d\n", (int)PTR_ERR(vma)); diff --git a/drivers/gpu/drm/i915/intel_uc.c b/drivers/gpu/drm/i915/intel_uc.c index aec2954..83b2516 100644 --- a/drivers/gpu/drm/i915/intel_uc.c +++ b/drivers/gpu/drm/i915/intel_uc.c @@ -86,6 +86,125 @@ void intel_uc_init_early(struct drm_i915_private *dev_priv) intel_guc_init_early(&dev_priv->guc); } +static u32 rc6_context_size(struct drm_i915_private *dev_priv) +{ + /* On BXT, the top of WOPCM is reserved for RC6 context */ + if (IS_GEN9_LP(dev_priv)) + return BXT_WOPCM_RC6_RESERVED; + + return 0; +} + +static int do_wopcm_partition(struct drm_i915_private *dev_priv, + u32 offset, u32 reserved_size) +{ + struct intel_wopcm_partition *wp = &dev_priv->wopcm_partition; + u32 aligned_offset = ALIGN(offset, WOPCM_OFFSET_ALIGNMENT); + + if (offset >= dev_priv->wopcm.size) + return -E2BIG; + + if (reserved_size >= dev_priv->wopcm.size) + return -E2BIG; + + if ((aligned_offset + reserved_size) >= dev_priv->wopcm.size) + return -E2BIG; + + wp->guc_wopcm_offset = aligned_offset; + wp->guc_wopcm_top = dev_priv->wopcm.size - wp->guc_wopcm_offset; + wp->guc_wopcm_size = wp->guc_wopcm_top - reserved_size; + + return 0; +} + +static int intel_uc_init_wopcm_partition(struct drm_i915_private *dev_priv) +{ + struct intel_wopcm_partition *wp = &dev_priv->wopcm_partition; + struct intel_uc_fw *guc_fw = &dev_priv->guc.fw; + struct intel_uc_fw *huc_fw = &dev_priv->huc.fw; + size_t huc_size, guc_size; + u32 offset; + u32 reserved; + u32 wopcm_base; + u32 delta; + int err; + + /*Return if WOPCM partition has been initialized*/ + if (wp->guc_wopcm_size) + return 0; + + GEM_BUG_ON(!dev_priv->wopcm.size); + + /*No need to do partition if failed to fetch both GuC and HuC FW*/ + if (guc_fw->fetch_status != INTEL_UC_FIRMWARE_SUCCESS && + huc_fw->fetch_status != INTEL_UC_FIRMWARE_SUCCESS) + return -EIO; + + huc_size = 0; + guc_size = 0; + offset = WOPCM_RESERVED_SIZE; + reserved = rc6_context_size(dev_priv); + + if (huc_fw->fetch_status == INTEL_UC_FIRMWARE_SUCCESS) + huc_size = huc_fw->header_size + huc_fw->ucode_size; + + err = do_wopcm_partition(dev_priv, offset + huc_size, reserved); + if (err) { + if (!huc_size) + goto pt_done; + + /*partition failed with HuC FW, block HuC loading*/ + huc_size = 0; + + /*partition without loading HuC FW*/ + err = do_wopcm_partition(dev_priv, offset, reserved); + if (err) + goto pt_done; + } + + /* + * Check hardware restriction on Gen9 + * GuC WOPCM size is at least 4 bytes larger than GuC WOPCM base due + * to hardware limitation on Gen9. + */ + if (IS_GEN9(dev_priv)) { + wopcm_base = wp->guc_wopcm_offset + GEN9_GUC_WOPCM_OFFSET; + if (unlikely(wopcm_base > wp->guc_wopcm_size)) + goto pt_done; + + delta = wp->guc_wopcm_size - wopcm_base; + if (unlikely(delta < GEN9_GUC_WOPCM_DELTA)) + goto pt_done; + } + + if (guc_fw->fetch_status == INTEL_UC_FIRMWARE_SUCCESS) { + guc_size = guc_fw->header_size + guc_fw->ucode_size; + /*need 8K stack for GuC*/ + guc_size += GUC_WOPCM_STACK_RESERVED; + } + + if (guc_size > wp->guc_wopcm_size) + guc_size = 0; + +pt_done: + if (!huc_size) { + DRM_ERROR("HuC firmware is too large to fit in WOPCM\n"); + intel_uc_fw_fini(huc_fw); + } + + if (!guc_size) { + DRM_ERROR("GuC firmware is too large to fit in WOPCM\n"); + intel_uc_fw_fini(guc_fw); + } + + DRM_DEBUG_DRIVER("GuC WOPCM offset %dKB, size %dKB, top %dKB\n", + wp->guc_wopcm_offset >> 10, + wp->guc_wopcm_size >> 10, + wp->guc_wopcm_top >> 10); + + return err; +} + void intel_uc_init_fw(struct drm_i915_private *dev_priv) { intel_uc_fw_fetch(dev_priv, &dev_priv->huc.fw); @@ -157,6 +276,11 @@ int intel_uc_init_hw(struct drm_i915_private *dev_priv) if (!i915_modparams.enable_guc_loading) return 0; + /*init WOPCM partition*/ + ret = intel_uc_init_wopcm_partition(dev_priv); + if (ret) + goto err_wopcm; + guc_disable_communication(guc); gen9_reset_guc_interrupts(dev_priv); @@ -176,7 +300,7 @@ int intel_uc_init_hw(struct drm_i915_private *dev_priv) /* init WOPCM */ I915_WRITE(GUC_WOPCM_SIZE, intel_guc_wopcm_size(dev_priv)); I915_WRITE(DMA_GUC_WOPCM_OFFSET, - GUC_WOPCM_OFFSET_VALUE | HUC_LOADING_AGENT_GUC); + intel_guc_wopcm_offset(dev_priv) | HUC_LOADING_AGENT_GUC); /* WaEnableuKernelHeaderValidFix:skl */ /* WaEnableGuCBootHashCheckNotSet:skl,bxt,kbl */ @@ -249,7 +373,7 @@ int intel_uc_init_hw(struct drm_i915_private *dev_priv) i915_guc_submission_fini(dev_priv); err_guc: i915_ggtt_disable_guc(dev_priv); - +err_wopcm: if (i915_modparams.enable_guc_loading > 1 || i915_modparams.enable_guc_submission > 1) { DRM_ERROR("GuC init failed. Firmware loading disabled.\n"); diff --git a/drivers/gpu/drm/i915/intel_uc_fw.c b/drivers/gpu/drm/i915/intel_uc_fw.c index 973888e..aefba13 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)) { + if (size > dev_priv->wopcm.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,8 @@ 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 | + intel_guc_wopcm_top(i915)); if (IS_ERR(vma)) { err = PTR_ERR(vma); DRM_DEBUG_DRIVER("%s fw ggtt-pin err=%d\n",