[PATCH 1/8] drm/i915/guc: Defer GuC message handling to tasklet

Michał Winiarski michal.winiarski at intel.com
Mon Mar 26 14:06:33 UTC 2018


Taking forcewake may be slow, and we need forcewake to read registers
which hold the type of message we're getting from GuC.
Rather than doing the forcewake dance in the IRQ, let's defer the
processing to the tasklet.

Coincidentally, we're also fixing a dmesg-warn "RPM wakelock ref not
held during HW access".

Reported-by: Marta Löfstedt <marta.lofstedt at intel.com>
Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=105710
Signed-off-by: Michał Winiarski <michal.winiarski at intel.com>
Cc: Chris Wilson <chris at chris-wilson.co.uk>
Cc: Daniele Ceraolo Spurio <daniele.ceraolospurio at intel.com>
Cc: Marta Löfstedt <marta.lofstedt at intel.com>
Cc: Michal Wajdeczko <michal.wajdeczko at intel.com>
---
 drivers/gpu/drm/i915/i915_irq.c  |  2 +-
 drivers/gpu/drm/i915/intel_guc.c | 60 ++++++++++++++++++++++------------------
 drivers/gpu/drm/i915/intel_guc.h | 10 +++----
 drivers/gpu/drm/i915/intel_uc.c  |  1 +
 4 files changed, 40 insertions(+), 33 deletions(-)

diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c
index 27aee25429b7..4b7e29bb3160 100644
--- a/drivers/gpu/drm/i915/i915_irq.c
+++ b/drivers/gpu/drm/i915/i915_irq.c
@@ -1766,7 +1766,7 @@ static void gen6_rps_irq_handler(struct drm_i915_private *dev_priv, u32 pm_iir)
 static void gen9_guc_irq_handler(struct drm_i915_private *dev_priv, u32 gt_iir)
 {
 	if (gt_iir & GEN9_GUC_TO_HOST_INT_EVENT)
-		intel_guc_to_host_event_handler(&dev_priv->guc);
+		tasklet_schedule(&dev_priv->guc.tasklet);
 }
 
 static void i9xx_pipestat_irq_reset(struct drm_i915_private *dev_priv)
diff --git a/drivers/gpu/drm/i915/intel_guc.c b/drivers/gpu/drm/i915/intel_guc.c
index 8f93f5bef8fd..875dd2d73f10 100644
--- a/drivers/gpu/drm/i915/intel_guc.c
+++ b/drivers/gpu/drm/i915/intel_guc.c
@@ -161,11 +161,44 @@ static void guc_shared_data_destroy(struct intel_guc *guc)
 	i915_vma_unpin_and_release(&guc->shared_data);
 }
 
+static void guc_to_host_event_handler(unsigned long data)
+{
+	struct intel_guc *guc = (struct intel_guc *)data;
+	struct drm_i915_private *dev_priv = guc_to_i915(guc);
+	u32 msg, val;
+
+	/*
+	 * Sample the log buffer flush related bits & clear them out now
+	 * itself from the message identity register to minimize the
+	 * probability of losing a flush interrupt, when there are back
+	 * to back flush interrupts.
+	 * There can be a new flush interrupt, for different log buffer
+	 * type (like for ISR), whilst Host is handling one (for DPC).
+	 * Since same bit is used in message register for ISR & DPC, it
+	 * could happen that GuC sets the bit for 2nd interrupt but Host
+	 * clears out the bit on handling the 1st interrupt.
+	 */
+	intel_runtime_pm_get(dev_priv);
+	spin_lock(&guc->irq_lock);
+	val = I915_READ(SOFT_SCRATCH(15));
+	msg = val & guc->msg_enabled_mask;
+	I915_WRITE(SOFT_SCRATCH(15), val & ~msg);
+	spin_unlock(&guc->irq_lock);
+	intel_runtime_pm_put(dev_priv);
+
+	if (msg & (INTEL_GUC_RECV_MSG_FLUSH_LOG_BUFFER |
+		   INTEL_GUC_RECV_MSG_CRASH_DUMP_POSTED))
+		intel_guc_log_handle_flush_event(&guc->log);
+}
+
 int intel_guc_init(struct intel_guc *guc)
 {
 	struct drm_i915_private *dev_priv = guc_to_i915(guc);
 	int ret;
 
+	tasklet_init(&guc->tasklet, guc_to_host_event_handler,
+		     (unsigned long)guc);
+
 	ret = guc_shared_data_create(guc);
 	if (ret)
 		return ret;
@@ -374,33 +407,6 @@ int intel_guc_send_mmio(struct intel_guc *guc, const u32 *action, u32 len)
 	return ret;
 }
 
-void intel_guc_to_host_event_handler(struct intel_guc *guc)
-{
-	struct drm_i915_private *dev_priv = guc_to_i915(guc);
-	u32 msg, val;
-
-	/*
-	 * Sample the log buffer flush related bits & clear them out now
-	 * itself from the message identity register to minimize the
-	 * probability of losing a flush interrupt, when there are back
-	 * to back flush interrupts.
-	 * There can be a new flush interrupt, for different log buffer
-	 * type (like for ISR), whilst Host is handling one (for DPC).
-	 * Since same bit is used in message register for ISR & DPC, it
-	 * could happen that GuC sets the bit for 2nd interrupt but Host
-	 * clears out the bit on handling the 1st interrupt.
-	 */
-	spin_lock(&guc->irq_lock);
-	val = I915_READ(SOFT_SCRATCH(15));
-	msg = val & guc->msg_enabled_mask;
-	I915_WRITE(SOFT_SCRATCH(15), val & ~msg);
-	spin_unlock(&guc->irq_lock);
-
-	if (msg & (INTEL_GUC_RECV_MSG_FLUSH_LOG_BUFFER |
-		   INTEL_GUC_RECV_MSG_CRASH_DUMP_POSTED))
-		intel_guc_log_handle_flush_event(&guc->log);
-}
-
 int intel_guc_sample_forcewake(struct intel_guc *guc)
 {
 	struct drm_i915_private *dev_priv = guc_to_i915(guc);
diff --git a/drivers/gpu/drm/i915/intel_guc.h b/drivers/gpu/drm/i915/intel_guc.h
index 13f3d1dbf38d..955d2131b97f 100644
--- a/drivers/gpu/drm/i915/intel_guc.h
+++ b/drivers/gpu/drm/i915/intel_guc.h
@@ -57,6 +57,7 @@ struct intel_guc {
 
 	/* intel_guc_recv interrupt related state */
 	spinlock_t irq_lock;
+	struct tasklet_struct tasklet;
 	bool interrupts_enabled;
 	unsigned int msg_enabled_mask;
 
@@ -142,7 +143,6 @@ int intel_guc_init(struct intel_guc *guc);
 void intel_guc_fini(struct intel_guc *guc);
 int intel_guc_send_nop(struct intel_guc *guc, const u32 *action, u32 len);
 int intel_guc_send_mmio(struct intel_guc *guc, const u32 *action, u32 len);
-void intel_guc_to_host_event_handler(struct intel_guc *guc);
 int intel_guc_sample_forcewake(struct intel_guc *guc);
 int intel_guc_auth_huc(struct intel_guc *guc, u32 rsa_offset);
 int intel_guc_suspend(struct intel_guc *guc);
@@ -157,16 +157,16 @@ static inline int intel_guc_sanitize(struct intel_guc *guc)
 
 static inline void intel_guc_enable_msg(struct intel_guc *guc, u32 mask)
 {
-	spin_lock_irq(&guc->irq_lock);
+	spin_lock_bh(&guc->irq_lock);
 	guc->msg_enabled_mask |= mask;
-	spin_unlock_irq(&guc->irq_lock);
+	spin_unlock_bh(&guc->irq_lock);
 }
 
 static inline void intel_guc_disable_msg(struct intel_guc *guc, u32 mask)
 {
-	spin_lock_irq(&guc->irq_lock);
+	spin_lock_bh(&guc->irq_lock);
 	guc->msg_enabled_mask &= ~mask;
-	spin_unlock_irq(&guc->irq_lock);
+	spin_unlock_bh(&guc->irq_lock);
 }
 
 #endif
diff --git a/drivers/gpu/drm/i915/intel_uc.c b/drivers/gpu/drm/i915/intel_uc.c
index 4aad8442e789..6d190f56ad08 100644
--- a/drivers/gpu/drm/i915/intel_uc.c
+++ b/drivers/gpu/drm/i915/intel_uc.c
@@ -244,6 +244,7 @@ static void guc_disable_communication(struct intel_guc *guc)
 		intel_guc_ct_disable(&guc->ct);
 
 	gen9_disable_guc_interrupts(dev_priv);
+	tasklet_kill(&guc->tasklet);
 
 	guc->send = intel_guc_send_nop;
 }
-- 
2.14.3



More information about the Intel-gfx-trybot mailing list