From patchwork Thu Oct 26 14:01:44 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Mika Kuoppala X-Patchwork-Id: 10028317 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 95CDE60381 for ; Thu, 26 Oct 2017 14:02:03 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 8611728E22 for ; Thu, 26 Oct 2017 14:02:03 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 794C528E27; Thu, 26 Oct 2017 14:02:03 +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 D1C1628E22 for ; Thu, 26 Oct 2017 14:02:02 +0000 (UTC) Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id 876D76E7BD; Thu, 26 Oct 2017 14:02:02 +0000 (UTC) X-Original-To: intel-gfx@lists.freedesktop.org Delivered-To: intel-gfx@lists.freedesktop.org Received: from mga11.intel.com (mga11.intel.com [192.55.52.93]) by gabe.freedesktop.org (Postfix) with ESMTPS id DBE9D6E1C2 for ; Thu, 26 Oct 2017 14:02:00 +0000 (UTC) Received: from orsmga003.jf.intel.com ([10.7.209.27]) by fmsmga102.fm.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 26 Oct 2017 07:01:59 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos; i="5.43,434,1503385200"; d="scan'208"; a="1029704416" Received: from rosetta.fi.intel.com ([10.237.72.186]) by orsmga003.jf.intel.com with ESMTP; 26 Oct 2017 07:01:55 -0700 Received: by rosetta.fi.intel.com (Postfix, from userid 1000) id A0BBA8402F4; Thu, 26 Oct 2017 17:01:45 +0300 (EEST) From: Mika Kuoppala To: intel-gfx@lists.freedesktop.org Date: Thu, 26 Oct 2017 17:01:44 +0300 Message-Id: <20171026140144.12267-1-mika.kuoppala@linux.intel.com> X-Mailer: git-send-email 2.11.0 Cc: Rodrigo Vivi Subject: [Intel-gfx] [PATCH] drm/i915: Fallback to reserve forcewake if primary ack missing 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 There is a possibility on gen9 hardware to miss the forcewake ack message. The recommended workaround is to use another free bit and toggle it until original bit is successfully acknowledged. The workaround is a bit misleadingly named as WaRsForcewakeAddDelayForAck. The reason for naming is most likely that workaround was named before the most recent recommendation evolved to use the reserve bit. Some future gen9 revs might or might not fix the underlying issue but the fallback to reserve bit dance can be considered as harmless: without the ack timeout we never reach the reserve bit forcewake. Thus as of now we adopt a blanket approach for all gen9 and leave the bypassing the reserve bit approach for future patches if corresponding hw revisions do appear. Commit 83e3337204b2 ("drm/i915: Increase maximum polling time to 50ms for forcewake request/clear ack") did increase the forcewake timeout. If the issue was a delayed ack, future work could include finding a suitable timeout value both for primary ack and reserve toggle to reduce the worst case latency. References: HSDES #1604254524 References: https://bugs.freedesktop.org/show_bug.cgi?id=102051 Cc: Chris Wilson Cc: Rodrigo Vivi Cc: Tvrtko Ursulin Cc: Joonas Lahtinen Cc: Sagar Arun Kamble Signed-off-by: Mika Kuoppala --- drivers/gpu/drm/i915/i915_reg.h | 5 +- drivers/gpu/drm/i915/intel_uncore.c | 112 +++++++++++++++++++++++++++++++++--- 2 files changed, 108 insertions(+), 9 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index f138eae82bf0..c04c634af5ae 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -7774,8 +7774,9 @@ enum { #define FORCEWAKE_ACK_MEDIA_GEN9 _MMIO(0x0D88) #define FORCEWAKE_ACK_RENDER_GEN9 _MMIO(0x0D84) #define FORCEWAKE_ACK_BLITTER_GEN9 _MMIO(0x130044) -#define FORCEWAKE_KERNEL 0x1 -#define FORCEWAKE_USER 0x2 +#define FORCEWAKE_KERNEL BIT(0) +#define FORCEWAKE_USER BIT(1) +#define FORCEWAKE_RESERVE BIT(12) #define FORCEWAKE_MT_ACK _MMIO(0x130040) #define ECOBUS _MMIO(0xa180) #define FORCEWAKE_MT_ENABLE (1<<5) diff --git a/drivers/gpu/drm/i915/intel_uncore.c b/drivers/gpu/drm/i915/intel_uncore.c index 20e3c65c0999..fc6d090244c5 100644 --- a/drivers/gpu/drm/i915/intel_uncore.c +++ b/drivers/gpu/drm/i915/intel_uncore.c @@ -69,17 +69,80 @@ fw_domain_arm_timer(struct intel_uncore_forcewake_domain *d) HRTIMER_MODE_REL); } +static inline bool +wait_ack_clear(const struct drm_i915_private *i915, + const struct intel_uncore_forcewake_domain *d, + const u32 ack) +{ + return wait_for_atomic((__raw_i915_read32(i915, d->reg_ack) & ack) == 0, + FORCEWAKE_ACK_TIMEOUT_MS); +} + +static inline bool +wait_ack_set(const struct drm_i915_private *i915, + const struct intel_uncore_forcewake_domain *d, + const u32 ack) +{ + return wait_for_atomic((__raw_i915_read32(i915, d->reg_ack) & ack), + FORCEWAKE_ACK_TIMEOUT_MS); +} + static inline void fw_domain_wait_ack_clear(const struct drm_i915_private *i915, const struct intel_uncore_forcewake_domain *d) { - if (wait_for_atomic((__raw_i915_read32(i915, d->reg_ack) & - FORCEWAKE_KERNEL) == 0, - FORCEWAKE_ACK_TIMEOUT_MS)) + if (wait_ack_clear(i915, d, FORCEWAKE_KERNEL)) DRM_ERROR("%s: timed out waiting for forcewake ack to clear.\n", intel_uncore_forcewake_domain_to_str(d->id)); } +enum ack_type { + ACK_CLEAR = 0, + ACK_SET +}; + +static bool +fw_domain_reserve_fallback(const struct drm_i915_private *i915, + const struct intel_uncore_forcewake_domain *d, + const enum ack_type type) +{ + bool timeout; + int retry = 10; + + /* Fallback to toggle another fw bit to wake up the gpu */ + do { + wait_ack_clear(i915, d, FORCEWAKE_RESERVE); + __raw_i915_write32(i915, d->reg_set, + _MASKED_BIT_ENABLE(FORCEWAKE_RESERVE)); + wait_ack_set(i915, d, FORCEWAKE_RESERVE); + + if (type == ACK_CLEAR) + timeout = wait_ack_clear(i915, d, FORCEWAKE_KERNEL); + else + timeout = wait_ack_set(i915, d, FORCEWAKE_KERNEL); + + __raw_i915_write32(i915, d->reg_set, + _MASKED_BIT_DISABLE(FORCEWAKE_RESERVE)); + } while (timeout && --retry); + + return timeout; +} + +static inline void +fw_domain_wait_ack_clear_reserve(const struct drm_i915_private *i915, + const struct intel_uncore_forcewake_domain *d) +{ + bool timeout; + + timeout = wait_ack_clear(i915, d, FORCEWAKE_KERNEL); + if (likely(!timeout)) + return; + + timeout = fw_domain_reserve_fallback(i915, d, ACK_CLEAR); + if (timeout) + fw_domain_wait_ack_clear(i915, d); +} + static inline void fw_domain_get(struct drm_i915_private *i915, const struct intel_uncore_forcewake_domain *d) @@ -91,14 +154,27 @@ static inline void fw_domain_wait_ack(const struct drm_i915_private *i915, const struct intel_uncore_forcewake_domain *d) { - if (wait_for_atomic((__raw_i915_read32(i915, d->reg_ack) & - FORCEWAKE_KERNEL), - FORCEWAKE_ACK_TIMEOUT_MS)) + if (wait_ack_set(i915, d, FORCEWAKE_KERNEL)) DRM_ERROR("%s: timed out waiting for forcewake ack request.\n", intel_uncore_forcewake_domain_to_str(d->id)); } static inline void +fw_domain_wait_ack_set_reserve(const struct drm_i915_private *i915, + const struct intel_uncore_forcewake_domain *d) +{ + bool timeout; + + timeout = wait_ack_set(i915, d, FORCEWAKE_KERNEL); + if (likely(!timeout)) + return; + + timeout = fw_domain_reserve_fallback(i915, d, ACK_SET); + if (timeout) + fw_domain_wait_ack(i915, d); +} + +static inline void fw_domain_put(const struct drm_i915_private *i915, const struct intel_uncore_forcewake_domain *d) { @@ -125,6 +201,26 @@ fw_domains_get(struct drm_i915_private *i915, enum forcewake_domains fw_domains) } static void +fw_domains_get_with_reserve(struct drm_i915_private *i915, + enum forcewake_domains fw_domains) +{ + struct intel_uncore_forcewake_domain *d; + unsigned int tmp; + + GEM_BUG_ON(fw_domains & ~i915->uncore.fw_domains); + + for_each_fw_domain_masked(d, fw_domains, i915, tmp) { + fw_domain_wait_ack_clear_reserve(i915, d); + fw_domain_get(i915, d); + } + + for_each_fw_domain_masked(d, fw_domains, i915, tmp) + fw_domain_wait_ack_set_reserve(i915, d); + + i915->uncore.fw_domains_active |= fw_domains; +} + +static void fw_domains_put(struct drm_i915_private *i915, enum forcewake_domains fw_domains) { struct intel_uncore_forcewake_domain *d; @@ -1142,7 +1238,9 @@ static void intel_uncore_fw_domains_init(struct drm_i915_private *dev_priv) } if (INTEL_GEN(dev_priv) >= 9) { - dev_priv->uncore.funcs.force_wake_get = fw_domains_get; + /* WaRsForcewakeAddDelayForAck:skl,bxt,kbl,glk,cfl,cnl */ + dev_priv->uncore.funcs.force_wake_get = + fw_domains_get_with_reserve; dev_priv->uncore.funcs.force_wake_put = fw_domains_put; fw_domain_init(dev_priv, FW_DOMAIN_ID_RENDER, FORCEWAKE_RENDER_GEN9,