[Intel-gfx] [RFC 3/8] drm/i915: dynamically allocate forcewake domains

Daniele Ceraolo Spurio daniele.ceraolospurio at intel.com
Thu Jun 6 21:52:12 UTC 2019


In an upcoming patch we will introduce a display uncore with no forcewake
domains, so let's avoid wasting memory and be ready to allocate only what
we need.

Signed-off-by: Daniele Ceraolo Spurio <daniele.ceraolospurio at intel.com>
---
 drivers/gpu/drm/i915/intel_uncore.c | 141 +++++++++++++++++-----------
 drivers/gpu/drm/i915/intel_uncore.h |  13 +--
 2 files changed, 92 insertions(+), 62 deletions(-)

diff --git a/drivers/gpu/drm/i915/intel_uncore.c b/drivers/gpu/drm/i915/intel_uncore.c
index ef7eed9237a0..30650e6e2f54 100644
--- a/drivers/gpu/drm/i915/intel_uncore.c
+++ b/drivers/gpu/drm/i915/intel_uncore.c
@@ -344,7 +344,7 @@ intel_uncore_fw_release_timer(struct hrtimer *timer)
 {
 	struct intel_uncore_forcewake_domain *domain =
 	       container_of(timer, struct intel_uncore_forcewake_domain, timer);
-	struct intel_uncore *uncore = forcewake_domain_to_uncore(domain);
+	struct intel_uncore *uncore = domain->uncore;
 	unsigned long irqflags;
 
 	assert_rpm_device_not_suspended(uncore->rpm);
@@ -1283,23 +1283,24 @@ do { \
 	(uncore)->funcs.read_fw_domains = x##_reg_read_fw_domains; \
 } while (0)
 
-static void fw_domain_init(struct intel_uncore *uncore,
+static int fw_domain_init(struct intel_uncore *uncore,
 			   enum forcewake_domain_id domain_id,
 			   i915_reg_t reg_set,
 			   i915_reg_t reg_ack)
 {
 	struct intel_uncore_forcewake_domain *d;
 
-	if (WARN_ON(domain_id >= FW_DOMAIN_ID_COUNT))
-		return;
-
-	d = &uncore->fw_domain[domain_id];
+	GEM_BUG_ON(domain_id >= FW_DOMAIN_ID_COUNT);
+	GEM_BUG_ON(uncore->fw_domain[domain_id]);
 
-	WARN_ON(d->wake_count);
+	d = kzalloc(sizeof(*d), GFP_KERNEL);
+	if (!d)
+		return -ENOMEM;
 
 	WARN_ON(!i915_mmio_reg_valid(reg_set));
 	WARN_ON(!i915_mmio_reg_valid(reg_ack));
 
+	d->uncore = uncore;
 	d->wake_count = 0;
 	d->reg_set = uncore->regs + i915_mmio_reg_offset(reg_set);
 	d->reg_ack = uncore->regs + i915_mmio_reg_offset(reg_ack);
@@ -1325,6 +1326,10 @@ static void fw_domain_init(struct intel_uncore *uncore,
 	uncore->fw_domains |= BIT(domain_id);
 
 	fw_domain_reset(d);
+
+	uncore->fw_domain[domain_id] = d;
+
+	return 0;
 }
 
 static void fw_domain_fini(struct intel_uncore *uncore,
@@ -1332,78 +1337,93 @@ static void fw_domain_fini(struct intel_uncore *uncore,
 {
 	struct intel_uncore_forcewake_domain *d;
 
-	if (WARN_ON(domain_id >= FW_DOMAIN_ID_COUNT))
-		return;
+	GEM_BUG_ON(domain_id >= FW_DOMAIN_ID_COUNT);
 
-	d = &uncore->fw_domain[domain_id];
+	d = fetch_and_zero(&uncore->fw_domain[domain_id]);
+	uncore->fw_domains &= ~BIT(domain_id);
 
-	WARN_ON(d->wake_count);
-	WARN_ON(hrtimer_cancel(&d->timer));
-	memset(d, 0, sizeof(*d));
+	if (d) {
+		WARN_ON(d->wake_count);
+		WARN_ON(hrtimer_cancel(&d->timer));
+		kfree(d);
+	}
+}
 
-	uncore->fw_domains &= ~BIT(domain_id);
+static void intel_uncore_fw_domains_fini(struct intel_uncore *uncore)
+{
+	struct intel_uncore_forcewake_domain *d;
+	int tmp;
+
+	for_each_fw_domain(d, uncore, tmp)
+		fw_domain_fini(uncore, d->id);
 }
 
-static void intel_uncore_fw_domains_init(struct intel_uncore *uncore)
+static int intel_uncore_fw_domains_init(struct intel_uncore *uncore)
 {
 	struct drm_i915_private *i915 = uncore_to_i915(uncore);
+	int ret;
+
+#define __fw_domain_init(id, set, ack) \
+	ret = fw_domain_init(uncore, id, set, ack); \
+	if (ret) \
+		goto out_clean;
 
 	if (!intel_uncore_has_forcewake(uncore))
-		return;
+		return 0;
 
 	if (INTEL_GEN(i915) >= 11) {
 		int i;
 
-		uncore->funcs.force_wake_get =
-			fw_domains_get_with_fallback;
+		uncore->funcs.force_wake_get = fw_domains_get_with_fallback;
 		uncore->funcs.force_wake_put = fw_domains_put;
-		fw_domain_init(uncore, FW_DOMAIN_ID_RENDER,
-			       FORCEWAKE_RENDER_GEN9,
-			       FORCEWAKE_ACK_RENDER_GEN9);
-		fw_domain_init(uncore, FW_DOMAIN_ID_BLITTER,
-			       FORCEWAKE_BLITTER_GEN9,
-			       FORCEWAKE_ACK_BLITTER_GEN9);
+		__fw_domain_init(FW_DOMAIN_ID_RENDER,
+				 FORCEWAKE_RENDER_GEN9,
+				 FORCEWAKE_ACK_RENDER_GEN9);
+		__fw_domain_init(FW_DOMAIN_ID_BLITTER,
+				 FORCEWAKE_BLITTER_GEN9,
+				 FORCEWAKE_ACK_BLITTER_GEN9);
+
 		for (i = 0; i < I915_MAX_VCS; i++) {
 			if (!HAS_ENGINE(i915, _VCS(i)))
 				continue;
 
-			fw_domain_init(uncore, FW_DOMAIN_ID_MEDIA_VDBOX0 + i,
-				       FORCEWAKE_MEDIA_VDBOX_GEN11(i),
-				       FORCEWAKE_ACK_MEDIA_VDBOX_GEN11(i));
+			__fw_domain_init(FW_DOMAIN_ID_MEDIA_VDBOX0 + i,
+					 FORCEWAKE_MEDIA_VDBOX_GEN11(i),
+					 FORCEWAKE_ACK_MEDIA_VDBOX_GEN11(i));
 		}
 		for (i = 0; i < I915_MAX_VECS; i++) {
 			if (!HAS_ENGINE(i915, _VECS(i)))
 				continue;
 
-			fw_domain_init(uncore, FW_DOMAIN_ID_MEDIA_VEBOX0 + i,
-				       FORCEWAKE_MEDIA_VEBOX_GEN11(i),
-				       FORCEWAKE_ACK_MEDIA_VEBOX_GEN11(i));
+			__fw_domain_init(FW_DOMAIN_ID_MEDIA_VEBOX0 + i,
+					 FORCEWAKE_MEDIA_VEBOX_GEN11(i),
+					 FORCEWAKE_ACK_MEDIA_VEBOX_GEN11(i));
 		}
 	} else if (IS_GEN_RANGE(i915, 9, 10)) {
-		uncore->funcs.force_wake_get =
-			fw_domains_get_with_fallback;
+		uncore->funcs.force_wake_get = fw_domains_get_with_fallback;
 		uncore->funcs.force_wake_put = fw_domains_put;
-		fw_domain_init(uncore, FW_DOMAIN_ID_RENDER,
-			       FORCEWAKE_RENDER_GEN9,
-			       FORCEWAKE_ACK_RENDER_GEN9);
-		fw_domain_init(uncore, FW_DOMAIN_ID_BLITTER,
-			       FORCEWAKE_BLITTER_GEN9,
-			       FORCEWAKE_ACK_BLITTER_GEN9);
-		fw_domain_init(uncore, FW_DOMAIN_ID_MEDIA,
-			       FORCEWAKE_MEDIA_GEN9, FORCEWAKE_ACK_MEDIA_GEN9);
+		__fw_domain_init(FW_DOMAIN_ID_RENDER,
+				 FORCEWAKE_RENDER_GEN9,
+				 FORCEWAKE_ACK_RENDER_GEN9);
+		__fw_domain_init(FW_DOMAIN_ID_BLITTER,
+				 FORCEWAKE_BLITTER_GEN9,
+				 FORCEWAKE_ACK_BLITTER_GEN9);
+		__fw_domain_init(FW_DOMAIN_ID_MEDIA,
+				 FORCEWAKE_MEDIA_GEN9,
+				 FORCEWAKE_ACK_MEDIA_GEN9);
 	} else if (IS_VALLEYVIEW(i915) || IS_CHERRYVIEW(i915)) {
 		uncore->funcs.force_wake_get = fw_domains_get;
 		uncore->funcs.force_wake_put = fw_domains_put;
-		fw_domain_init(uncore, FW_DOMAIN_ID_RENDER,
-			       FORCEWAKE_VLV, FORCEWAKE_ACK_VLV);
-		fw_domain_init(uncore, FW_DOMAIN_ID_MEDIA,
-			       FORCEWAKE_MEDIA_VLV, FORCEWAKE_ACK_MEDIA_VLV);
+		__fw_domain_init(FW_DOMAIN_ID_RENDER,
+				 FORCEWAKE_VLV, FORCEWAKE_ACK_VLV);
+		__fw_domain_init(FW_DOMAIN_ID_MEDIA,
+				 FORCEWAKE_MEDIA_VLV, FORCEWAKE_ACK_MEDIA_VLV);
 	} else if (IS_HASWELL(i915) || IS_BROADWELL(i915)) {
 		uncore->funcs.force_wake_get =
 			fw_domains_get_with_thread_status;
 		uncore->funcs.force_wake_put = fw_domains_put;
-		fw_domain_init(uncore, FW_DOMAIN_ID_RENDER,
-			       FORCEWAKE_MT, FORCEWAKE_ACK_HSW);
+		__fw_domain_init(FW_DOMAIN_ID_RENDER,
+				 FORCEWAKE_MT, FORCEWAKE_ACK_HSW);
 	} else if (IS_IVYBRIDGE(i915)) {
 		u32 ecobus;
 
@@ -1430,8 +1450,8 @@ static void intel_uncore_fw_domains_init(struct intel_uncore *uncore)
 		__raw_uncore_write32(uncore, FORCEWAKE, 0);
 		__raw_posting_read(uncore, ECOBUS);
 
-		fw_domain_init(uncore, FW_DOMAIN_ID_RENDER,
-			       FORCEWAKE_MT, FORCEWAKE_MT_ACK);
+		__fw_domain_init(FW_DOMAIN_ID_RENDER,
+				 FORCEWAKE_MT, FORCEWAKE_MT_ACK);
 
 		spin_lock_irq(&uncore->lock);
 		fw_domains_get_with_thread_status(uncore, FORCEWAKE_RENDER);
@@ -1442,19 +1462,28 @@ static void intel_uncore_fw_domains_init(struct intel_uncore *uncore)
 		if (!(ecobus & FORCEWAKE_MT_ENABLE)) {
 			DRM_INFO("No MT forcewake available on Ivybridge, this can result in issues\n");
 			DRM_INFO("when using vblank-synced partial screen updates.\n");
-			fw_domain_init(uncore, FW_DOMAIN_ID_RENDER,
-				       FORCEWAKE, FORCEWAKE_ACK);
+			__fw_domain_init(FW_DOMAIN_ID_RENDER,
+					 FORCEWAKE, FORCEWAKE_ACK);
 		}
 	} else if (IS_GEN(i915, 6)) {
 		uncore->funcs.force_wake_get =
 			fw_domains_get_with_thread_status;
 		uncore->funcs.force_wake_put = fw_domains_put;
-		fw_domain_init(uncore, FW_DOMAIN_ID_RENDER,
-			       FORCEWAKE, FORCEWAKE_ACK);
+		__fw_domain_init(FW_DOMAIN_ID_RENDER,
+				 FORCEWAKE, FORCEWAKE_ACK);
 	}
 
+#undef __fw_domain_init
+
 	/* All future platforms are expected to require complex power gating */
 	WARN_ON(uncore->fw_domains == 0);
+
+	return 0;
+
+out_clean:
+	intel_uncore_fw_domains_fini(uncore);
+	return ret;
+
 }
 
 #define ASSIGN_FW_DOMAINS_TABLE(uncore, d) \
@@ -1554,7 +1583,12 @@ int intel_uncore_init_mmio(struct intel_uncore *uncore)
 	if (INTEL_GEN(i915) > 5 && !intel_vgpu_active(i915))
 		uncore->flags |= UNCORE_HAS_FORCEWAKE;
 
-	intel_uncore_fw_domains_init(uncore);
+	ret = intel_uncore_fw_domains_init(uncore);
+	if (ret) {
+		uncore_mmio_cleanup(uncore);
+		return ret;
+	}
+
 	__intel_uncore_early_sanitize(uncore, 0);
 
 	uncore->unclaimed_mmio_check = 1;
@@ -1662,6 +1696,7 @@ void intel_uncore_fini_mmio(struct intel_uncore *uncore)
 	iosf_mbi_unregister_pmic_bus_access_notifier_unlocked(
 		&uncore->pmic_bus_access_nb);
 	intel_uncore_forcewake_reset(uncore);
+	intel_uncore_fw_domains_fini(uncore);
 	iosf_mbi_punit_release();
 	uncore_mmio_cleanup(uncore);
 }
diff --git a/drivers/gpu/drm/i915/intel_uncore.h b/drivers/gpu/drm/i915/intel_uncore.h
index bf06b6b16892..2bb80962e7c5 100644
--- a/drivers/gpu/drm/i915/intel_uncore.h
+++ b/drivers/gpu/drm/i915/intel_uncore.h
@@ -125,6 +125,7 @@ struct intel_uncore {
 	enum forcewake_domains fw_domains_saved; /* user domains saved for S3 */
 
 	struct intel_uncore_forcewake_domain {
+		struct intel_uncore *uncore;
 		enum forcewake_domain_id id;
 		enum forcewake_domains mask;
 		unsigned int wake_count;
@@ -132,7 +133,7 @@ struct intel_uncore {
 		struct hrtimer timer;
 		u32 __iomem *reg_set;
 		u32 __iomem *reg_ack;
-	} fw_domain[FW_DOMAIN_ID_COUNT];
+	} *fw_domain[FW_DOMAIN_ID_COUNT];
 
 	struct {
 		unsigned int count;
@@ -146,18 +147,12 @@ struct intel_uncore {
 
 /* Iterate over initialised fw domains */
 #define for_each_fw_domain_masked(domain__, mask__, uncore__, tmp__) \
-	for (tmp__ = (mask__); \
-	     tmp__ ? (domain__ = &(uncore__)->fw_domain[__mask_next_bit(tmp__)]), 1 : 0;)
+	for (tmp__ = (mask__); tmp__ ;) \
+		for_each_if(domain__ = (uncore__)->fw_domain[__mask_next_bit(tmp__)])
 
 #define for_each_fw_domain(domain__, uncore__, tmp__) \
 	for_each_fw_domain_masked(domain__, (uncore__)->fw_domains, uncore__, tmp__)
 
-static inline struct intel_uncore *
-forcewake_domain_to_uncore(const struct intel_uncore_forcewake_domain *d)
-{
-	return container_of(d, struct intel_uncore, fw_domain[d->id]);
-}
-
 static inline bool
 intel_uncore_has_forcewake(const struct intel_uncore *uncore)
 {
-- 
2.20.1



More information about the Intel-gfx mailing list