@@ -2340,6 +2340,12 @@ static int i915_guc_info(struct seq_file *m, void *data)
GEM_BUG_ON(!guc->execbuf_client);
GEM_BUG_ON(!guc->preempt_client);
+ seq_puts(m, "GuC Interrupt Clients: ");
+ if (test_bit(GUC_INTR_CLIENT_LOG, &guc->interrupt_clients))
+ seq_puts(m, "GuC Logging\n");
+ else
+ seq_puts(m, "None\n");
+
seq_printf(m, "Doorbell map:\n");
seq_printf(m, "\t%*pb\n", GUC_NUM_DOORBELLS, guc->doorbell_bitmap);
seq_printf(m, "Doorbell next cacheline: 0x%x\n\n", guc->db_cacheline);
@@ -522,28 +522,53 @@ void intel_guc_reset_interrupts(struct intel_guc *guc)
spin_unlock_irq(&dev_priv->irq_lock);
}
-void intel_guc_enable_interrupts(struct intel_guc *guc)
+static void __intel_guc_enable_interrupts(struct intel_guc *guc)
+{
+ struct drm_i915_private *dev_priv = guc_to_i915(guc);
+
+ lockdep_assert_held(&dev_priv->irq_lock);
+
+ WARN_ON_ONCE(I915_READ(gen6_pm_iir(dev_priv)) &
+ dev_priv->pm_guc_events);
+ gen6_enable_pm_irq(dev_priv, dev_priv->pm_guc_events);
+}
+
+void intel_guc_enable_interrupts(struct intel_guc *guc,
+ enum intel_guc_intr_client id)
{
struct drm_i915_private *dev_priv = guc_to_i915(guc);
spin_lock_irq(&dev_priv->irq_lock);
- if (!guc->interrupts_enabled) {
- WARN_ON_ONCE(I915_READ(gen6_pm_iir(dev_priv)) &
- dev_priv->pm_guc_events);
- guc->interrupts_enabled = true;
- gen6_enable_pm_irq(dev_priv, dev_priv->pm_guc_events);
- }
+
+ if (!guc->interrupt_clients)
+ __intel_guc_enable_interrupts(guc);
+ __set_bit(id, &guc->interrupt_clients);
+
spin_unlock_irq(&dev_priv->irq_lock);
}
-void intel_guc_disable_interrupts(struct intel_guc *guc)
+static void __intel_guc_disable_interrupts(struct intel_guc *guc)
{
struct drm_i915_private *dev_priv = guc_to_i915(guc);
- spin_lock_irq(&dev_priv->irq_lock);
- guc->interrupts_enabled = false;
+ lockdep_assert_held(&dev_priv->irq_lock);
gen6_disable_pm_irq(dev_priv, dev_priv->pm_guc_events);
+}
+
+void intel_guc_disable_interrupts(struct intel_guc *guc,
+ enum intel_guc_intr_client id)
+{
+ struct drm_i915_private *dev_priv = guc_to_i915(guc);
+
+ spin_lock_irq(&dev_priv->irq_lock);
+
+ __clear_bit(id, &guc->interrupt_clients);
+ if (guc->interrupt_clients) {
+ spin_unlock_irq(&dev_priv->irq_lock);
+ return;
+ }
+ __intel_guc_disable_interrupts(guc);
spin_unlock_irq(&dev_priv->irq_lock);
synchronize_irq(dev_priv->drm.irq);
@@ -34,6 +34,11 @@
#include "intel_uc_fw.h"
#include "i915_vma.h"
+enum intel_guc_intr_client {
+ GUC_INTR_CLIENT_LOG = 0,
+ GUC_INTR_CLIENT_COUNT
+};
+
struct guc_preempt_work {
struct work_struct work;
struct intel_engine_cs *engine;
@@ -53,7 +58,7 @@ struct intel_guc {
struct drm_i915_gem_object *load_err_log;
/* intel_guc_recv interrupt related state */
- bool interrupts_enabled;
+ unsigned long interrupt_clients;
struct i915_vma *ads_vma;
struct i915_vma *stage_desc_pool;
@@ -132,8 +137,10 @@ static inline u32 guc_ggtt_offset(struct i915_vma *vma)
struct i915_vma *intel_guc_allocate_vma(struct intel_guc *guc, u32 size);
u32 intel_guc_wopcm_size(struct drm_i915_private *dev_priv);
void intel_guc_reset_interrupts(struct intel_guc *guc);
-void intel_guc_enable_interrupts(struct intel_guc *guc);
-void intel_guc_disable_interrupts(struct intel_guc *guc);
+void intel_guc_enable_interrupts(struct intel_guc *guc,
+ enum intel_guc_intr_client id);
+void intel_guc_disable_interrupts(struct intel_guc *guc,
+ enum intel_guc_intr_client id);
void intel_guc_irq_handler(struct intel_guc *guc, u32 pm_iir);
#endif
@@ -592,7 +592,6 @@ int i915_guc_log_control(struct drm_i915_private *dev_priv, u64 control_val)
return ret;
}
- /* GuC logging is currently the only user of Guc2Host interrupts */
intel_guc_log_enable_interrupts(guc);
} else {
/* Once logging is disabled, GuC won't generate logs & send an
@@ -628,7 +627,6 @@ void i915_guc_log_unregister(struct drm_i915_private *dev_priv)
return;
mutex_lock(&dev_priv->drm.struct_mutex);
- /* GuC logging is currently the only user of Guc2Host interrupts */
intel_runtime_pm_get(dev_priv);
intel_guc_log_disable_interrupts(&dev_priv->guc);
intel_runtime_pm_put(dev_priv);
@@ -640,11 +638,11 @@ void i915_guc_log_unregister(struct drm_i915_private *dev_priv)
void intel_guc_log_enable_interrupts(struct intel_guc *guc)
{
if (guc->log.level >= 0)
- intel_guc_enable_interrupts(guc);
+ intel_guc_enable_interrupts(guc, GUC_INTR_CLIENT_LOG);
}
void intel_guc_log_disable_interrupts(struct intel_guc *guc)
{
if (guc->log.level >= 0)
- intel_guc_disable_interrupts(guc);
+ intel_guc_disable_interrupts(guc, GUC_INTR_CLIENT_LOG);
}
This patch adds support to enable/disable GuC interrupts for different features without impacting other's need. Currently GuC log capture and CT buffer receive mechanisms use the GuC interrupts. GuC interrupts are currently enabled and disabled in different logging scenarios all gated by log level. v2: Rebase with all GuC interrupt handlers moved to intel_guc.c. Handling multiple clients for GuC interrupts enable/disable. (Michal Wajdeczko) v3: Removed spin lock and using test_bit in i915_guc_info. Prepared low level helpers to get/put GuC interrupts that can be reused during suspend/resume. (Tvrtko) v4: Rebase. Removed comments about logging being sole user of interrupts. s/guc_intr_client/intel_guc_intr_client. Reverted function names to enable/disable_interrupts from get/put_interrupts as applicable. (Michal) Signed-off-by: Sagar Arun Kamble <sagar.a.kamble@intel.com> Cc: Michal Wajdeczko <michal.wajdeczko@intel.com> Cc: Daniele Ceraolo Spurio <daniele.ceraolospurio@intel.com> Cc: Tvrtko Ursulin <tvrtko.ursulin@intel.com> Cc: Chris Wilson <chris@chris-wilson.co.uk> Cc: Joonas Lahtinen <joonas.lahtinen@linux.intel.com> --- drivers/gpu/drm/i915/i915_debugfs.c | 6 +++++ drivers/gpu/drm/i915/intel_guc.c | 45 ++++++++++++++++++++++++++++-------- drivers/gpu/drm/i915/intel_guc.h | 13 ++++++++--- drivers/gpu/drm/i915/intel_guc_log.c | 6 ++--- 4 files changed, 53 insertions(+), 17 deletions(-)