@@ -67,6 +67,7 @@ void intel_guc_init_early(struct intel_guc *guc)
intel_guc_log_init_early(guc);
mutex_init(&guc->send_mutex);
+ spin_lock_init(&guc->irq_lock);
guc->send = intel_guc_send_nop;
guc->notify = gen8_guc_raise_irq;
}
@@ -367,7 +368,7 @@ 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)
{
struct drm_i915_private *dev_priv = guc_to_i915(guc);
- u32 msg, flush;
+ u32 msg, val;
/*
* Sample the log buffer flush related bits & clear them out now
@@ -380,24 +381,18 @@ void intel_guc_to_host_event_handler(struct intel_guc *guc)
* could happen that GuC sets the bit for 2nd interrupt but Host
* clears out the bit on handling the 1st interrupt.
*/
-
- msg = I915_READ(SOFT_SCRATCH(15));
- flush = msg & (INTEL_GUC_RECV_MSG_CRASH_DUMP_POSTED |
- INTEL_GUC_RECV_MSG_FLUSH_LOG_BUFFER);
- if (flush) {
- /* Clear the message bits that are handled */
- I915_WRITE(SOFT_SCRATCH(15), msg & ~flush);
-
- /* Handle flush interrupt in bottom half */
+ 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)) {
queue_work(guc->log.runtime.flush_wq,
&guc->log.runtime.flush_work);
guc->log.flush_interrupt_count++;
- } else {
- /*
- * Not clearing of unhandled event bits won't result in
- * re-triggering of the interrupt.
- */
}
}
@@ -53,7 +53,9 @@ struct intel_guc {
struct drm_i915_gem_object *load_err_log;
/* intel_guc_recv interrupt related state */
+ spinlock_t irq_lock;
bool interrupts_enabled;
+ unsigned int msg_enabled_mask;
struct i915_vma *ads_vma;
struct i915_vma *stage_desc_pool;
@@ -592,6 +592,22 @@ int intel_guc_log_create(struct intel_guc *guc)
return ret;
}
+static void guc_log_flush_irq_enable(struct intel_guc *guc)
+{
+ spin_lock_irq(&guc->irq_lock);
+ guc->msg_enabled_mask |= INTEL_GUC_RECV_MSG_FLUSH_LOG_BUFFER |
+ INTEL_GUC_RECV_MSG_CRASH_DUMP_POSTED;
+ spin_unlock_irq(&guc->irq_lock);
+}
+
+static void guc_log_flush_irq_disable(struct intel_guc *guc)
+{
+ spin_lock_irq(&guc->irq_lock);
+ guc->msg_enabled_mask &= ~(INTEL_GUC_RECV_MSG_FLUSH_LOG_BUFFER |
+ INTEL_GUC_RECV_MSG_CRASH_DUMP_POSTED);
+ spin_unlock_irq(&guc->irq_lock);
+}
+
void intel_guc_log_destroy(struct intel_guc *guc)
{
guc_log_runtime_destroy(guc);
@@ -696,12 +712,7 @@ int intel_guc_log_register(struct intel_guc *guc)
if (ret)
goto err_runtime;
- /* GuC logging is currently the only user of Guc2Host interrupts */
- mutex_lock(&i915->drm.struct_mutex);
- intel_runtime_pm_get(i915);
- gen9_enable_guc_interrupts(i915);
- intel_runtime_pm_put(i915);
- mutex_unlock(&i915->drm.struct_mutex);
+ guc_log_flush_irq_enable(guc);
return 0;
@@ -719,6 +730,8 @@ void intel_guc_log_unregister(struct intel_guc *guc)
{
struct drm_i915_private *i915 = guc_to_i915(guc);
+ guc_log_flush_irq_disable(guc);
+
/*
* Once logging is disabled, GuC won't generate logs & send an
* interrupt. But there could be some data in the log buffer
@@ -728,11 +741,6 @@ void intel_guc_log_unregister(struct intel_guc *guc)
guc_flush_logs(guc);
mutex_lock(&i915->drm.struct_mutex);
- /* GuC logging is currently the only user of Guc2Host interrupts */
- intel_runtime_pm_get(i915);
- gen9_disable_guc_interrupts(i915);
- intel_runtime_pm_put(i915);
-
guc_log_runtime_destroy(guc);
mutex_unlock(&i915->drm.struct_mutex);
@@ -245,6 +245,8 @@ static int guc_enable_communication(struct intel_guc *guc)
{
struct drm_i915_private *dev_priv = guc_to_i915(guc);
+ gen9_enable_guc_interrupts(dev_priv);
+
if (HAS_GUC_CT(dev_priv))
return intel_guc_enable_ct(guc);
@@ -259,6 +261,8 @@ static void guc_disable_communication(struct intel_guc *guc)
if (HAS_GUC_CT(dev_priv))
intel_guc_disable_ct(guc);
+ gen9_disable_guc_interrupts(dev_priv);
+
guc->send = intel_guc_send_nop;
}
@@ -397,12 +401,9 @@ int intel_uc_init_hw(struct drm_i915_private *dev_priv)
}
if (USES_GUC_SUBMISSION(dev_priv)) {
- if (i915_modparams.guc_log_level)
- gen9_enable_guc_interrupts(dev_priv);
-
ret = intel_guc_submission_enable(guc);
if (ret)
- goto err_interrupts;
+ goto err_communication;
}
dev_info(dev_priv->drm.dev, "GuC firmware version %u.%u\n",
@@ -417,8 +418,6 @@ int intel_uc_init_hw(struct drm_i915_private *dev_priv)
/*
* We've failed to load the firmware :(
*/
-err_interrupts:
- gen9_disable_guc_interrupts(dev_priv);
err_communication:
guc_disable_communication(guc);
err_log_capture:
@@ -448,9 +447,6 @@ void intel_uc_fini_hw(struct drm_i915_private *dev_priv)
intel_guc_submission_disable(guc);
guc_disable_communication(guc);
-
- if (USES_GUC_SUBMISSION(dev_priv))
- gen9_disable_guc_interrupts(dev_priv);
}
int intel_uc_suspend(struct drm_i915_private *i915)