From patchwork Fri Mar 23 00:07:46 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jackie Li X-Patchwork-Id: 10302521 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 75FBA600CC for ; Fri, 23 Mar 2018 00:09:48 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 66A9C28AAE for ; Fri, 23 Mar 2018 00:09:48 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 5B65D28AB1; Fri, 23 Mar 2018 00:09:48 +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 B965828AAE for ; Fri, 23 Mar 2018 00:09:47 +0000 (UTC) Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id 6576B6E251; Fri, 23 Mar 2018 00:09:46 +0000 (UTC) X-Original-To: intel-gfx@lists.freedesktop.org Delivered-To: intel-gfx@lists.freedesktop.org Received: from mga17.intel.com (mga17.intel.com [192.55.52.151]) by gabe.freedesktop.org (Postfix) with ESMTPS id 6A7146E23F for ; Fri, 23 Mar 2018 00:09:41 +0000 (UTC) X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from fmsmga005.fm.intel.com ([10.253.24.32]) by fmsmga107.fm.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 22 Mar 2018 17:09:41 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.48,347,1517904000"; d="scan'208";a="214074167" Received: from yli84-z170x-ud5.fm.intel.com ([10.19.83.123]) by fmsmga005.fm.intel.com with ESMTP; 22 Mar 2018 17:09:41 -0700 From: Jackie Li To: intel-gfx@lists.freedesktop.org Date: Thu, 22 Mar 2018 17:07:46 -0700 Message-Id: <1521763667-14387-3-git-send-email-yaodong.li@intel.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1521763667-14387-1-git-send-email-yaodong.li@intel.com> References: <1521763667-14387-1-git-send-email-yaodong.li@intel.com> Subject: [Intel-gfx] [PATCH v2 3/4] drm/i915: Add code to accept valid locked WOPCM register values X-BeenThere: intel-gfx@lists.freedesktop.org X-Mailman-Version: 2.1.23 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 In current code, we only compare the locked WOPCM register values with the calculated values. However, we can continue loading GuC/HuC firmware if the locked (or partially locked) values were valid for current GuC/HuC firmware sizes. This patch added a new code path to verify whether the locked register values can be used for GuC/HuC firmware loading, it will recalculate the verify the new values if these registers were partially locked, so that we won't fail the GuC/HuC firmware loading even if the locked register values are different from the calculated ones. v2: - Update WOPCM register only if it's not locked Signed-off-by: Jackie Li Cc: Michal Wajdeczko Cc: Sagar Arun Kamble Cc: Michal Winiarski Cc: John Spotswood --- drivers/gpu/drm/i915/intel_wopcm.c | 225 +++++++++++++++++++++++++++++++------ 1 file changed, 189 insertions(+), 36 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_wopcm.c b/drivers/gpu/drm/i915/intel_wopcm.c index babb158..add23e3 100644 --- a/drivers/gpu/drm/i915/intel_wopcm.c +++ b/drivers/gpu/drm/i915/intel_wopcm.c @@ -138,6 +138,53 @@ static inline int check_hw_restriction(struct drm_i915_private *i915, return err; } +static inline u32 calculate_min_guc_wopcm_base(u32 huc_fw_size) +{ + return ALIGN(huc_fw_size + WOPCM_RESERVED_SIZE, + GUC_WOPCM_OFFSET_ALIGNMENT); +} + +static inline u32 calculate_min_guc_wopcm_size(u32 guc_fw_size) +{ + return guc_fw_size + GUC_WOPCM_RESERVED + GUC_WOPCM_STACK_RESERVED; +} + +static inline int calculate_max_guc_wopcm_size(struct intel_wopcm *wopcm, + u32 guc_wopcm_base, + u32 *guc_wopcm_size) +{ + struct drm_i915_private *i915 = wopcm_to_i915(wopcm); + u32 ctx_rsvd = context_reserved_size(i915); + + if (guc_wopcm_base >= wopcm->size || + (guc_wopcm_base + ctx_rsvd) >= wopcm->size) { + DRM_ERROR("GuC WOPCM base (%uKiB) is too big.\n", + guc_wopcm_base / 1024); + return -E2BIG; + } + + *guc_wopcm_size = + (wopcm->size - guc_wopcm_base - ctx_rsvd) & GUC_WOPCM_SIZE_MASK; + + return 0; +} + +static inline int verify_calculated_values(struct drm_i915_private *i915, + u32 guc_fw_size, u32 huc_fw_size, + u32 guc_wopcm_base, + u32 guc_wopcm_size) +{ + if (guc_wopcm_size < calculate_min_guc_wopcm_size(guc_fw_size)) { + DRM_ERROR("Need %uKiB WOPCM for GuC FW, %uKiB available.\n", + calculate_min_guc_wopcm_size(guc_fw_size), + guc_wopcm_size / 1024); + return -E2BIG; + } + + return check_hw_restriction(i915, guc_wopcm_base, guc_wopcm_size, + huc_fw_size); +} + /** * intel_wopcm_init() - Initialize the WOPCM structure. * @wopcm: pointer to intel_wopcm. @@ -155,10 +202,8 @@ int intel_wopcm_init(struct intel_wopcm *wopcm) struct drm_i915_private *i915 = wopcm_to_i915(wopcm); u32 guc_fw_size = intel_uc_fw_get_upload_size(&i915->guc.fw); u32 huc_fw_size = intel_uc_fw_get_upload_size(&i915->huc.fw); - u32 ctx_rsvd = context_reserved_size(i915); u32 guc_wopcm_base; u32 guc_wopcm_size; - u32 guc_wopcm_rsvd; int err; GEM_BUG_ON(!wopcm->size); @@ -175,30 +220,18 @@ int intel_wopcm_init(struct intel_wopcm *wopcm) return -E2BIG; } - guc_wopcm_base = ALIGN(huc_fw_size + WOPCM_RESERVED_SIZE, - GUC_WOPCM_OFFSET_ALIGNMENT); - if ((guc_wopcm_base + ctx_rsvd) >= wopcm->size) { - DRM_ERROR("GuC WOPCM base (%uKiB) is too big.\n", - guc_wopcm_base / 1024); - return -E2BIG; - } - - guc_wopcm_size = wopcm->size - guc_wopcm_base - ctx_rsvd; - guc_wopcm_size &= GUC_WOPCM_SIZE_MASK; + guc_wopcm_base = calculate_min_guc_wopcm_base(huc_fw_size); + err = calculate_max_guc_wopcm_size(wopcm, guc_wopcm_base, + &guc_wopcm_size); + if (err) + return err; DRM_DEBUG_DRIVER("Calculated GuC WOPCM Region: [%uKiB, %uKiB)\n", - guc_wopcm_base / 1024, guc_wopcm_size / 1024); + guc_wopcm_base / 1024, + (guc_wopcm_base + guc_wopcm_size) / 1024); - guc_wopcm_rsvd = GUC_WOPCM_RESERVED + GUC_WOPCM_STACK_RESERVED; - if ((guc_fw_size + guc_wopcm_rsvd) > guc_wopcm_size) { - DRM_ERROR("Need %uKiB WOPCM for GuC, %uKiB available.\n", - (guc_fw_size + guc_wopcm_rsvd) / 1024, - guc_wopcm_size / 1024); - return -E2BIG; - } - - err = check_hw_restriction(i915, guc_wopcm_base, guc_wopcm_size, - huc_fw_size); + err = verify_calculated_values(i915, guc_fw_size, huc_fw_size, + guc_wopcm_base, guc_wopcm_size); if (err) return err; @@ -208,6 +241,104 @@ int intel_wopcm_init(struct intel_wopcm *wopcm) return 0; } +static inline int verify_locked_values(struct intel_wopcm *wopcm, + u32 guc_wopcm_base, u32 guc_wopcm_size) +{ + struct drm_i915_private *i915 = wopcm_to_i915(wopcm); + u32 guc_fw_size = intel_uc_fw_get_upload_size(&i915->guc.fw); + u32 huc_fw_size = intel_uc_fw_get_upload_size(&i915->huc.fw); + u32 ctx_rsvd = context_reserved_size(i915); + + /* + * Locked GuC WOPCM base and size could be any values which are large + * enough to lead to a wrap around after performing add operations. + */ + if (guc_wopcm_base >= wopcm->size) { + DRM_ERROR("Locked base value %uKiB >= WOPCM size %uKiB.\n", + guc_wopcm_base / 1024, + wopcm->size / 1024); + return -E2BIG; + } + + if (guc_wopcm_size >= wopcm->size) { + DRM_ERROR("Locked size value %uKiB >= WOPCM size %uKiB.\n", + guc_wopcm_base / 1024, + wopcm->size / 1024); + return -E2BIG; + } + + if (guc_wopcm_base + guc_wopcm_size + ctx_rsvd > wopcm->size) { + DRM_ERROR("Need %uKiB WOPCM in total, %uKiB available.\n", + (guc_wopcm_base + guc_wopcm_size + ctx_rsvd) / 1024, + (wopcm->size) / 1024); + return -E2BIG; + } + + if (guc_wopcm_base < calculate_min_guc_wopcm_base(huc_fw_size)) { + DRM_ERROR("Need %uKiB WOPCM for HuC FW, %uKiB available.\n", + calculate_min_guc_wopcm_base(huc_fw_size) / 1024, + guc_wopcm_base / 1024); + return -E2BIG; + } + + return verify_calculated_values(i915, guc_fw_size, huc_fw_size, + guc_wopcm_base, guc_wopcm_size); +} + +static inline int verify_locked_values_and_update(struct intel_wopcm *wopcm, + bool *update_size_reg, + bool *update_offset_reg) +{ + struct drm_i915_private *dev_priv = wopcm_to_i915(wopcm); + u32 huc_fw_size = intel_uc_fw_get_upload_size(&dev_priv->huc.fw); + u32 size_val = I915_READ(GUC_WOPCM_SIZE); + u32 offset_val = I915_READ(DMA_GUC_WOPCM_OFFSET); + bool offset_reg_locked = offset_val & GUC_WOPCM_OFFSET_VALID; + bool size_reg_locked = size_val & GUC_WOPCM_SIZE_LOCKED; + u32 guc_wopcm_base = offset_val & GUC_WOPCM_OFFSET_MASK; + u32 guc_wopcm_size = size_val & GUC_WOPCM_SIZE_MASK; + int err; + + *update_size_reg = !size_reg_locked; + *update_offset_reg = !offset_reg_locked; + + if (!offset_reg_locked && !size_reg_locked) + return 0; + + if (guc_wopcm_base == wopcm->guc.base && + guc_wopcm_size == wopcm->guc.size) + return 0; + + if (USES_HUC(dev_priv) && offset_reg_locked && + !(offset_val & HUC_LOADING_AGENT_GUC)) { + DRM_ERROR("HUC_LOADING_AGENT_GUC isn't locked for USES_HUC.\n"); + return -EIO; + } + + if (!offset_reg_locked) + guc_wopcm_base = calculate_min_guc_wopcm_base(huc_fw_size); + + if (!size_reg_locked) { + err = calculate_max_guc_wopcm_size(wopcm, guc_wopcm_base, + &guc_wopcm_size); + if (err) + return err; + } + + DRM_DEBUG_DRIVER("Recalculated GuC WOPCM Region: [%uKiB, %uKiB)\n", + guc_wopcm_base / 1024, + (guc_wopcm_base + guc_wopcm_size) / 1024); + + err = verify_locked_values(wopcm, guc_wopcm_base, guc_wopcm_size); + if (err) + return err; + + wopcm->guc.size = guc_wopcm_size; + wopcm->guc.base = guc_wopcm_base; + + return 0; +} + static inline int write_and_verify(struct drm_i915_private *dev_priv, i915_reg_t reg, u32 val, u32 mask, u32 locked_bit) @@ -231,11 +362,14 @@ static inline int write_and_verify(struct drm_i915_private *dev_priv, * will verify the register values to make sure the registers are locked with * correct values. * - * Return: 0 on success. -EIO if registers were locked with incorrect values. + * Return: 0 on success. Minus error code if registered were locked with + * incorrect values.-EIO if registers failed to lock with correct values. */ int intel_wopcm_init_hw(struct intel_wopcm *wopcm) { struct drm_i915_private *dev_priv = wopcm_to_i915(wopcm); + bool update_size_reg; + bool update_offset_reg; int err; if (!USES_GUC(dev_priv)) @@ -245,27 +379,46 @@ int intel_wopcm_init_hw(struct intel_wopcm *wopcm) GEM_BUG_ON(!wopcm->guc.size); GEM_BUG_ON(!wopcm->guc.base); - err = write_and_verify(dev_priv, GUC_WOPCM_SIZE, wopcm->guc.size, - GUC_WOPCM_SIZE_MASK | GUC_WOPCM_SIZE_LOCKED, - GUC_WOPCM_SIZE_LOCKED); - if (err) + err = verify_locked_values_and_update(wopcm, &update_size_reg, + &update_offset_reg); + if (err) { + DRM_ERROR("WOPCM registers are locked with invalid values.\n"); goto err_out; + } - err = write_and_verify(dev_priv, DMA_GUC_WOPCM_OFFSET, - wopcm->guc.base | HUC_LOADING_AGENT_GUC, - GUC_WOPCM_OFFSET_MASK | HUC_LOADING_AGENT_GUC | - GUC_WOPCM_OFFSET_VALID, - GUC_WOPCM_OFFSET_VALID); - if (err) - goto err_out; + if (update_size_reg) { + err = write_and_verify(dev_priv, GUC_WOPCM_SIZE, + wopcm->guc.size, + GUC_WOPCM_SIZE_MASK | + GUC_WOPCM_SIZE_LOCKED, + GUC_WOPCM_SIZE_LOCKED); + if (err) { + DRM_ERROR("Failed to GuC WOPCM size with %#x.\n", + wopcm->guc.size); + goto err_out; + } + } + if (update_offset_reg) { + err = write_and_verify(dev_priv, DMA_GUC_WOPCM_OFFSET, + wopcm->guc.base | HUC_LOADING_AGENT_GUC, + GUC_WOPCM_OFFSET_MASK | + HUC_LOADING_AGENT_GUC | + GUC_WOPCM_OFFSET_VALID, + GUC_WOPCM_OFFSET_VALID); + if (err) { + DRM_ERROR("Failed to GuC WOPCM offset with %#x.\n", + wopcm->guc.base); + goto err_out; + } + } return 0; err_out: - DRM_ERROR("Failed to init WOPCM registers:\n"); DRM_ERROR("DMA_GUC_WOPCM_OFFSET=%#x\n", I915_READ(DMA_GUC_WOPCM_OFFSET)); DRM_ERROR("GUC_WOPCM_SIZE=%#x\n", I915_READ(GUC_WOPCM_SIZE)); + DRM_ERROR("A system reboot is required.\n"); return err; }