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,
