Commit 26705e20 authored by Sagar Arun Kamble's avatar Sagar Arun Kamble Committed by Tvrtko Ursulin

drm/i915: Support for GuC interrupts

There are certain types of interrupts which Host can receive from GuC.
GuC ukernel sends an interrupt to Host for certain events, like for
example retrieve/consume the logs generated by ukernel.
This patch adds support to receive interrupts from GuC but currently
enables & partially handles only the interrupt sent by GuC ukernel.
Future patches will add support for handling other interrupt types.

v2:
- Use common low level routines for PM IER/IIR programming (Chris)
- Rename interrupt functions to gen9_xxx from gen8_xxx (Chris)
- Replace disabling of wake ref asserts with rpm get/put (Chris)

v3:
- Update comments for more clarity. (Tvrtko)
- Remove the masking of GuC interrupt, which was kept masked till the
  start of bottom half, its not really needed as there is only a
  single instance of work item & wq is ordered. (Tvrtko)

v4:
- Rebase.
- Rename guc_events to pm_guc_events so as to be indicative of the
  register/control block it is associated with. (Chris)
- Add handling for back to back log buffer flush interrupts.

v5:
- Move the read & clearing of register, containing Guc2Host message
  bits, outside the irq spinlock. (Tvrtko)

v6:
- Move the log buffer flush interrupt related stuff to the following
  patch so as to do only generic bits in this patch. (Tvrtko)
- Rebase.

v7:
- Remove the interrupts_enabled check from gen9_guc_irq_handler, want to
  process that last interrupt also before disabling the interrupt, sync
  against the work queued by irq handler will be done by caller disabling
  the interrupt.
Signed-off-by: default avatarSagar Arun Kamble <sagar.a.kamble@intel.com>
Signed-off-by: default avatarAkash Goel <akash.goel@intel.com>
Reviewed-by: default avatarTvrtko Ursulin <tvrtko.ursulin@intel.com>
Signed-off-by: default avatarTvrtko Ursulin <tvrtko.ursulin@intel.com>
parent f4e9af4f
...@@ -1839,6 +1839,7 @@ struct drm_i915_private { ...@@ -1839,6 +1839,7 @@ struct drm_i915_private {
u32 pm_imr; u32 pm_imr;
u32 pm_ier; u32 pm_ier;
u32 pm_rps_events; u32 pm_rps_events;
u32 pm_guc_events;
u32 pipestat_irq_mask[I915_MAX_PIPES]; u32 pipestat_irq_mask[I915_MAX_PIPES];
struct i915_hotplug hotplug; struct i915_hotplug hotplug;
......
...@@ -1086,6 +1086,8 @@ int intel_guc_suspend(struct drm_device *dev) ...@@ -1086,6 +1086,8 @@ int intel_guc_suspend(struct drm_device *dev)
if (guc->guc_fw.guc_fw_load_status != GUC_FIRMWARE_SUCCESS) if (guc->guc_fw.guc_fw_load_status != GUC_FIRMWARE_SUCCESS)
return 0; return 0;
gen9_disable_guc_interrupts(dev_priv);
ctx = dev_priv->kernel_context; ctx = dev_priv->kernel_context;
data[0] = HOST2GUC_ACTION_ENTER_S_STATE; data[0] = HOST2GUC_ACTION_ENTER_S_STATE;
...@@ -1112,6 +1114,9 @@ int intel_guc_resume(struct drm_device *dev) ...@@ -1112,6 +1114,9 @@ int intel_guc_resume(struct drm_device *dev)
if (guc->guc_fw.guc_fw_load_status != GUC_FIRMWARE_SUCCESS) if (guc->guc_fw.guc_fw_load_status != GUC_FIRMWARE_SUCCESS)
return 0; return 0;
if (i915.guc_log_level >= 0)
gen9_enable_guc_interrupts(dev_priv);
ctx = dev_priv->kernel_context; ctx = dev_priv->kernel_context;
data[0] = HOST2GUC_ACTION_EXIT_S_STATE; data[0] = HOST2GUC_ACTION_EXIT_S_STATE;
......
...@@ -170,6 +170,7 @@ static void gen5_assert_iir_is_zero(struct drm_i915_private *dev_priv, ...@@ -170,6 +170,7 @@ static void gen5_assert_iir_is_zero(struct drm_i915_private *dev_priv,
} while (0) } while (0)
static void gen6_rps_irq_handler(struct drm_i915_private *dev_priv, u32 pm_iir); 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 pm_iir);
/* For display hotplug interrupt */ /* For display hotplug interrupt */
static inline void static inline void
...@@ -417,6 +418,38 @@ void gen6_disable_rps_interrupts(struct drm_i915_private *dev_priv) ...@@ -417,6 +418,38 @@ void gen6_disable_rps_interrupts(struct drm_i915_private *dev_priv)
gen6_reset_rps_interrupts(dev_priv); gen6_reset_rps_interrupts(dev_priv);
} }
void gen9_reset_guc_interrupts(struct drm_i915_private *dev_priv)
{
spin_lock_irq(&dev_priv->irq_lock);
gen6_reset_pm_iir(dev_priv, dev_priv->pm_guc_events);
spin_unlock_irq(&dev_priv->irq_lock);
}
void gen9_enable_guc_interrupts(struct drm_i915_private *dev_priv)
{
spin_lock_irq(&dev_priv->irq_lock);
if (!dev_priv->guc.interrupts_enabled) {
WARN_ON_ONCE(I915_READ(gen6_pm_iir(dev_priv)) &
dev_priv->pm_guc_events);
dev_priv->guc.interrupts_enabled = true;
gen6_enable_pm_irq(dev_priv, dev_priv->pm_guc_events);
}
spin_unlock_irq(&dev_priv->irq_lock);
}
void gen9_disable_guc_interrupts(struct drm_i915_private *dev_priv)
{
spin_lock_irq(&dev_priv->irq_lock);
dev_priv->guc.interrupts_enabled = false;
gen6_disable_pm_irq(dev_priv, dev_priv->pm_guc_events);
spin_unlock_irq(&dev_priv->irq_lock);
synchronize_irq(dev_priv->drm.irq);
gen9_reset_guc_interrupts(dev_priv);
}
/** /**
* bdw_update_port_irq - update DE port interrupt * bdw_update_port_irq - update DE port interrupt
* @dev_priv: driver private * @dev_priv: driver private
...@@ -1346,11 +1379,13 @@ static irqreturn_t gen8_gt_irq_ack(struct drm_i915_private *dev_priv, ...@@ -1346,11 +1379,13 @@ static irqreturn_t gen8_gt_irq_ack(struct drm_i915_private *dev_priv,
DRM_ERROR("The master control interrupt lied (GT3)!\n"); DRM_ERROR("The master control interrupt lied (GT3)!\n");
} }
if (master_ctl & GEN8_GT_PM_IRQ) { if (master_ctl & (GEN8_GT_PM_IRQ | GEN8_GT_GUC_IRQ)) {
gt_iir[2] = I915_READ_FW(GEN8_GT_IIR(2)); gt_iir[2] = I915_READ_FW(GEN8_GT_IIR(2));
if (gt_iir[2] & dev_priv->pm_rps_events) { if (gt_iir[2] & (dev_priv->pm_rps_events |
dev_priv->pm_guc_events)) {
I915_WRITE_FW(GEN8_GT_IIR(2), I915_WRITE_FW(GEN8_GT_IIR(2),
gt_iir[2] & dev_priv->pm_rps_events); gt_iir[2] & (dev_priv->pm_rps_events |
dev_priv->pm_guc_events));
ret = IRQ_HANDLED; ret = IRQ_HANDLED;
} else } else
DRM_ERROR("The master control interrupt lied (PM)!\n"); DRM_ERROR("The master control interrupt lied (PM)!\n");
...@@ -1382,6 +1417,9 @@ static void gen8_gt_irq_handler(struct drm_i915_private *dev_priv, ...@@ -1382,6 +1417,9 @@ static void gen8_gt_irq_handler(struct drm_i915_private *dev_priv,
if (gt_iir[2] & dev_priv->pm_rps_events) if (gt_iir[2] & dev_priv->pm_rps_events)
gen6_rps_irq_handler(dev_priv, gt_iir[2]); gen6_rps_irq_handler(dev_priv, gt_iir[2]);
if (gt_iir[2] & dev_priv->pm_guc_events)
gen9_guc_irq_handler(dev_priv, gt_iir[2]);
} }
static bool bxt_port_hotplug_long_detect(enum port port, u32 val) static bool bxt_port_hotplug_long_detect(enum port port, u32 val)
...@@ -1628,6 +1666,13 @@ static void gen6_rps_irq_handler(struct drm_i915_private *dev_priv, u32 pm_iir) ...@@ -1628,6 +1666,13 @@ 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) {
/* TODO: Handle events for which GuC interrupted host */
}
}
static bool intel_pipe_handle_vblank(struct drm_i915_private *dev_priv, static bool intel_pipe_handle_vblank(struct drm_i915_private *dev_priv,
enum pipe pipe) enum pipe pipe)
{ {
...@@ -3699,7 +3744,7 @@ static void gen8_gt_irq_postinstall(struct drm_i915_private *dev_priv) ...@@ -3699,7 +3744,7 @@ static void gen8_gt_irq_postinstall(struct drm_i915_private *dev_priv)
GEN8_IRQ_INIT_NDX(GT, 1, ~gt_interrupts[1], gt_interrupts[1]); GEN8_IRQ_INIT_NDX(GT, 1, ~gt_interrupts[1], gt_interrupts[1]);
/* /*
* RPS interrupts will get enabled/disabled on demand when RPS itself * RPS interrupts will get enabled/disabled on demand when RPS itself
* is enabled/disabled. * is enabled/disabled. Same wil be the case for GuC interrupts.
*/ */
GEN8_IRQ_INIT_NDX(GT, 2, dev_priv->pm_imr, dev_priv->pm_ier); GEN8_IRQ_INIT_NDX(GT, 2, dev_priv->pm_imr, dev_priv->pm_ier);
GEN8_IRQ_INIT_NDX(GT, 3, ~gt_interrupts[3], gt_interrupts[3]); GEN8_IRQ_INIT_NDX(GT, 3, ~gt_interrupts[3], gt_interrupts[3]);
...@@ -4485,6 +4530,9 @@ void intel_irq_init(struct drm_i915_private *dev_priv) ...@@ -4485,6 +4530,9 @@ void intel_irq_init(struct drm_i915_private *dev_priv)
INIT_WORK(&dev_priv->rps.work, gen6_pm_rps_work); INIT_WORK(&dev_priv->rps.work, gen6_pm_rps_work);
INIT_WORK(&dev_priv->l3_parity.error_work, ivybridge_parity_work); INIT_WORK(&dev_priv->l3_parity.error_work, ivybridge_parity_work);
if (HAS_GUC_SCHED(dev))
dev_priv->pm_guc_events = GEN9_GUC_TO_HOST_INT_EVENT;
/* Let's track the enabled rps events */ /* Let's track the enabled rps events */
if (IS_VALLEYVIEW(dev_priv)) if (IS_VALLEYVIEW(dev_priv))
/* WaGsvRC0ResidencyMethod:vlv */ /* WaGsvRC0ResidencyMethod:vlv */
......
...@@ -6016,6 +6016,7 @@ enum { ...@@ -6016,6 +6016,7 @@ enum {
#define GEN8_DE_PIPE_A_IRQ (1<<16) #define GEN8_DE_PIPE_A_IRQ (1<<16)
#define GEN8_DE_PIPE_IRQ(pipe) (1<<(16+(pipe))) #define GEN8_DE_PIPE_IRQ(pipe) (1<<(16+(pipe)))
#define GEN8_GT_VECS_IRQ (1<<6) #define GEN8_GT_VECS_IRQ (1<<6)
#define GEN8_GT_GUC_IRQ (1<<5)
#define GEN8_GT_PM_IRQ (1<<4) #define GEN8_GT_PM_IRQ (1<<4)
#define GEN8_GT_VCS2_IRQ (1<<3) #define GEN8_GT_VCS2_IRQ (1<<3)
#define GEN8_GT_VCS1_IRQ (1<<2) #define GEN8_GT_VCS1_IRQ (1<<2)
...@@ -6027,6 +6028,16 @@ enum { ...@@ -6027,6 +6028,16 @@ enum {
#define GEN8_GT_IIR(which) _MMIO(0x44308 + (0x10 * (which))) #define GEN8_GT_IIR(which) _MMIO(0x44308 + (0x10 * (which)))
#define GEN8_GT_IER(which) _MMIO(0x4430c + (0x10 * (which))) #define GEN8_GT_IER(which) _MMIO(0x4430c + (0x10 * (which)))
#define GEN9_GUC_TO_HOST_INT_EVENT (1<<31)
#define GEN9_GUC_EXEC_ERROR_EVENT (1<<30)
#define GEN9_GUC_DISPLAY_EVENT (1<<29)
#define GEN9_GUC_SEMA_SIGNAL_EVENT (1<<28)
#define GEN9_GUC_IOMMU_MSG_EVENT (1<<27)
#define GEN9_GUC_DB_RING_EVENT (1<<26)
#define GEN9_GUC_DMA_DONE_EVENT (1<<25)
#define GEN9_GUC_FATAL_ERROR_EVENT (1<<24)
#define GEN9_GUC_NOTIFICATION_EVENT (1<<23)
#define GEN8_RCS_IRQ_SHIFT 0 #define GEN8_RCS_IRQ_SHIFT 0
#define GEN8_BCS_IRQ_SHIFT 16 #define GEN8_BCS_IRQ_SHIFT 16
#define GEN8_VCS1_IRQ_SHIFT 0 #define GEN8_VCS1_IRQ_SHIFT 0
......
...@@ -1148,6 +1148,9 @@ void gen8_irq_power_well_post_enable(struct drm_i915_private *dev_priv, ...@@ -1148,6 +1148,9 @@ void gen8_irq_power_well_post_enable(struct drm_i915_private *dev_priv,
unsigned int pipe_mask); unsigned int pipe_mask);
void gen8_irq_power_well_pre_disable(struct drm_i915_private *dev_priv, void gen8_irq_power_well_pre_disable(struct drm_i915_private *dev_priv,
unsigned int pipe_mask); unsigned int pipe_mask);
void gen9_reset_guc_interrupts(struct drm_i915_private *dev_priv);
void gen9_enable_guc_interrupts(struct drm_i915_private *dev_priv);
void gen9_disable_guc_interrupts(struct drm_i915_private *dev_priv);
/* intel_crt.c */ /* intel_crt.c */
void intel_crt_init(struct drm_device *dev); void intel_crt_init(struct drm_device *dev);
......
...@@ -132,6 +132,9 @@ struct intel_guc { ...@@ -132,6 +132,9 @@ struct intel_guc {
struct intel_guc_fw guc_fw; struct intel_guc_fw guc_fw;
struct intel_guc_log log; struct intel_guc_log log;
/* GuC2Host interrupt related state */
bool interrupts_enabled;
struct i915_vma *ads_vma; struct i915_vma *ads_vma;
struct i915_vma *ctx_pool_vma; struct i915_vma *ctx_pool_vma;
struct ida ctx_ids; struct ida ctx_ids;
......
...@@ -485,6 +485,7 @@ int intel_guc_setup(struct drm_device *dev) ...@@ -485,6 +485,7 @@ int intel_guc_setup(struct drm_device *dev)
} }
guc_interrupts_release(dev_priv); guc_interrupts_release(dev_priv);
gen9_reset_guc_interrupts(dev_priv);
guc_fw->guc_fw_load_status = GUC_FIRMWARE_PENDING; guc_fw->guc_fw_load_status = GUC_FIRMWARE_PENDING;
...@@ -529,6 +530,9 @@ int intel_guc_setup(struct drm_device *dev) ...@@ -529,6 +530,9 @@ int intel_guc_setup(struct drm_device *dev)
intel_guc_fw_status_repr(guc_fw->guc_fw_load_status)); intel_guc_fw_status_repr(guc_fw->guc_fw_load_status));
if (i915.enable_guc_submission) { if (i915.enable_guc_submission) {
if (i915.guc_log_level >= 0)
gen9_enable_guc_interrupts(dev_priv);
err = i915_guc_submission_enable(dev_priv); err = i915_guc_submission_enable(dev_priv);
if (err) if (err)
goto fail; goto fail;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment