Message ID | 1399294059-20748-2-git-send-email-deepak.s@linux.intel.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
On Mon, May 05, 2014 at 06:17:30PM +0530, deepak.s@linux.intel.com wrote: > From: Ben Widawsky <benjamin.widawsky@intel.com> > > Almost all of it is reusable from the existing code. The primary > difference is we need to do even less in the interrupt handler, since > interrupts are not shared in the same way. > > The patch is mostly a copy-paste of the existing snb+ code, with updates > to the relevant parts requiring changes to the interrupt handling. As > such it /should/ be relatively trivial. It's highly likely that I missed > some places where I need a gen8 version of the PM interrupts, but it has > become invisible to me by now. > > This patch could probably be split into adding the new functions, > followed by actually handling the interrupts. Since the code is > currently disabled (and broken) I think the patch stands better by > itself. > > v2: Move the commit about not touching the ringbuffer interrupt to the > snb_* function where it belongs (Rodrigo) > > v3: Rebased on Paulo's runtime PM changes > > v4: Not well validated, but rebase on > commit 730488b2eddded4497f63f70867b1256cd9e117c > Author: Paulo Zanoni <paulo.r.zanoni@intel.com> > Date: Fri Mar 7 20:12:32 2014 -0300 > > drm/i915: kill dev_priv->pm.regsave > > v5: Rebased on latest code base. (Deepak) > > v6: Remove conflict markers, Unnecessary empty line and use right > IIR interrupt (Ville) > > Signed-off-by: Ben Widawsky <ben@bwidawsk.net> > Signed-off-by: Deepak S <deepak.s@linux.intel.com> > --- > drivers/gpu/drm/i915/i915_irq.c | 75 ++++++++++++++++++++++++++++++++++++++-- > drivers/gpu/drm/i915/i915_reg.h | 1 + > drivers/gpu/drm/i915/intel_drv.h | 2 ++ > drivers/gpu/drm/i915/intel_pm.c | 38 ++++++++++++++++++-- > 4 files changed, 112 insertions(+), 4 deletions(-) > > diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c > index 2d76183..6af51ad 100644 > --- a/drivers/gpu/drm/i915/i915_irq.c > +++ b/drivers/gpu/drm/i915/i915_irq.c > @@ -248,6 +248,49 @@ static bool ivb_can_enable_err_int(struct drm_device *dev) > return true; > } > > +/** > + * bdw_update_pm_irq - update GT interrupt 2 > + * @dev_priv: driver private > + * @interrupt_mask: mask of interrupt bits to update > + * @enabled_irq_mask: mask of interrupt bits to enable > + * > + * Copied from the snb function, updated with relevant register offsets > + */ > +static void bdw_update_pm_irq(struct drm_i915_private *dev_priv, > + uint32_t interrupt_mask, > + uint32_t enabled_irq_mask) > +{ > + uint32_t new_val; > + > + assert_spin_locked(&dev_priv->irq_lock); > + > + if (dev_priv->pm.irqs_disabled) { > + WARN(1, "IRQs disabled\n"); > + return; > + } Could be just 'if (WARN...' just like in the snb function. > + > + new_val = dev_priv->pm_irq_mask; > + new_val &= ~interrupt_mask; > + new_val |= (~enabled_irq_mask & interrupt_mask); > + > + if (new_val != dev_priv->pm_irq_mask) { > + dev_priv->pm_irq_mask = new_val; > + I915_WRITE(GEN8_GT_IMR(2), I915_READ(GEN8_GT_IMR(2)) | > + dev_priv->pm_irq_mask); I just realized that this doesn't actually clear the old bits. I think we should just kill the RMW here and mandate that all users of GT_IMR(2) need to use this function. Also you're forgetting to initialize pm_irq_mask. I guess it should be initialized in gen8_gt_irq_postinstall() to match the gen6 code. > + POSTING_READ(GEN8_GT_IMR(2)); > + } > +} > + > +void bdw_enable_pm_irq(struct drm_i915_private *dev_priv, uint32_t mask) > +{ > + bdw_update_pm_irq(dev_priv, mask, mask); > +} > + > +void bdw_disable_pm_irq(struct drm_i915_private *dev_priv, uint32_t mask) > +{ > + bdw_update_pm_irq(dev_priv, mask, 0); > +} > + > static bool cpt_can_enable_serr_int(struct drm_device *dev) > { > struct drm_i915_private *dev_priv = dev->dev_private; > @@ -1098,8 +1141,12 @@ static void gen6_pm_rps_work(struct work_struct *work) > spin_lock_irq(&dev_priv->irq_lock); > pm_iir = dev_priv->rps.pm_iir; > dev_priv->rps.pm_iir = 0; > - /* Make sure not to corrupt PMIMR state used by ringbuffer code */ > - snb_enable_pm_irq(dev_priv, dev_priv->pm_rps_events); > + if (IS_BROADWELL(dev_priv->dev)) > + bdw_enable_pm_irq(dev_priv, dev_priv->pm_rps_events); > + else { > + /* Make sure not to corrupt PMIMR state used by ringbuffer */ > + snb_enable_pm_irq(dev_priv, dev_priv->pm_rps_events); > + } > spin_unlock_irq(&dev_priv->irq_lock); > > /* Make sure we didn't queue anything we're not going to process. */ > @@ -1296,6 +1343,19 @@ static void snb_gt_irq_handler(struct drm_device *dev, > ivybridge_parity_error_irq_handler(dev, gt_iir); > } > > +static void gen8_rps_irq_handler(struct drm_i915_private *dev_priv, u32 pm_iir) > +{ > + if ((pm_iir & dev_priv->pm_rps_events) == 0) > + return; > + > + spin_lock(&dev_priv->irq_lock); > + dev_priv->rps.pm_iir |= pm_iir & dev_priv->pm_rps_events; > + bdw_disable_pm_irq(dev_priv, pm_iir & dev_priv->pm_rps_events); > + spin_unlock(&dev_priv->irq_lock); > + > + queue_work(dev_priv->wq, &dev_priv->rps.work); > +} > + > static irqreturn_t gen8_gt_irq_handler(struct drm_device *dev, > struct drm_i915_private *dev_priv, > u32 master_ctl) > @@ -1334,6 +1394,17 @@ static irqreturn_t gen8_gt_irq_handler(struct drm_device *dev, > DRM_ERROR("The master control interrupt lied (GT1)!\n"); > } > > + if (master_ctl & GEN8_GT_PM_IRQ) { > + tmp = I915_READ(GEN8_GT_IIR(2)); > + if (tmp & dev_priv->pm_rps_events) { > + ret = IRQ_HANDLED; > + gen8_rps_irq_handler(dev_priv, tmp); > + I915_WRITE(GEN8_GT_IIR(2), > + tmp & dev_priv->pm_rps_events); > + } else > + DRM_ERROR("The master control interrupt lied (PM)!\n"); > + } > + > if (master_ctl & GEN8_GT_VECS_IRQ) { > tmp = I915_READ(GEN8_GT_IIR(3)); > if (tmp) { > diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h > index 0eff337..ca4f8b9 100644 > --- a/drivers/gpu/drm/i915/i915_reg.h > +++ b/drivers/gpu/drm/i915/i915_reg.h > @@ -4194,6 +4194,7 @@ enum punit_power_well { > #define GEN8_DE_PIPE_A_IRQ (1<<16) > #define GEN8_DE_PIPE_IRQ(pipe) (1<<(16+pipe)) > #define GEN8_GT_VECS_IRQ (1<<6) > +#define GEN8_GT_PM_IRQ (1<<4) > #define GEN8_GT_VCS2_IRQ (1<<3) > #define GEN8_GT_VCS1_IRQ (1<<2) > #define GEN8_GT_BCS_IRQ (1<<1) > diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h > index d8b540b..d560a9b 100644 > --- a/drivers/gpu/drm/i915/intel_drv.h > +++ b/drivers/gpu/drm/i915/intel_drv.h > @@ -653,6 +653,8 @@ void ilk_enable_gt_irq(struct drm_i915_private *dev_priv, uint32_t mask); > void ilk_disable_gt_irq(struct drm_i915_private *dev_priv, uint32_t mask); > void snb_enable_pm_irq(struct drm_i915_private *dev_priv, uint32_t mask); > void snb_disable_pm_irq(struct drm_i915_private *dev_priv, uint32_t mask); > +void bdw_enable_pm_irq(struct drm_i915_private *dev_priv, uint32_t mask); > +void bdw_disable_pm_irq(struct drm_i915_private *dev_priv, uint32_t mask); > void intel_runtime_pm_disable_interrupts(struct drm_device *dev); > void intel_runtime_pm_restore_interrupts(struct drm_device *dev); > int intel_get_crtc_scanline(struct intel_crtc *crtc); > diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c > index 834c49c..0e69c97 100644 > --- a/drivers/gpu/drm/i915/intel_pm.c > +++ b/drivers/gpu/drm/i915/intel_pm.c > @@ -3246,6 +3246,26 @@ void valleyview_set_rps(struct drm_device *dev, u8 val) > trace_intel_gpu_freq_change(vlv_gpu_freq(dev_priv, val)); > } > > +static void gen8_disable_rps_interrupts(struct drm_device *dev) > +{ > + struct drm_i915_private *dev_priv = dev->dev_private; > + > + I915_WRITE(GEN6_PMINTRMSK, 0xffffffff); > + I915_WRITE(GEN8_GT_IER(2), I915_READ(GEN8_GT_IER(2)) & > + ~dev_priv->pm_rps_events); > + /* Complete PM interrupt masking here doesn't race with the rps work > + * item again unmasking PM interrupts because that is using a different > + * register (GEN8_GT_IMR(2)) to mask PM interrupts. The only risk is in > + * leaving stale bits in GEN8_GT_IIR(2) and GEN8_GT_IMR(2) which > + * gen8_enable_rps will clean up. */ > + > + spin_lock_irq(&dev_priv->irq_lock); > + dev_priv->rps.pm_iir = 0; > + spin_unlock_irq(&dev_priv->irq_lock); > + > + I915_WRITE(GEN8_GT_IIR(2), dev_priv->pm_rps_events); > +} > + > static void gen6_disable_rps_interrupts(struct drm_device *dev) > { > struct drm_i915_private *dev_priv = dev->dev_private; > @@ -3272,7 +3292,10 @@ static void gen6_disable_rps(struct drm_device *dev) > I915_WRITE(GEN6_RC_CONTROL, 0); > I915_WRITE(GEN6_RPNSWREQ, 1 << 31); > > - gen6_disable_rps_interrupts(dev); > + if (IS_BROADWELL(dev)) > + gen8_disable_rps_interrupts(dev); > + else > + gen6_disable_rps_interrupts(dev); > } > > static void valleyview_disable_rps(struct drm_device *dev) > @@ -3344,6 +3367,17 @@ int intel_enable_rc6(const struct drm_device *dev) > return i915.enable_rc6; > } > > +static void gen8_enable_rps_interrupts(struct drm_device *dev) > +{ > + struct drm_i915_private *dev_priv = dev->dev_private; > + > + spin_lock_irq(&dev_priv->irq_lock); > + WARN_ON(dev_priv->rps.pm_iir); > + bdw_enable_pm_irq(dev_priv, dev_priv->pm_rps_events); > + I915_WRITE(GEN8_GT_IIR(2), dev_priv->pm_rps_events); > + spin_unlock_irq(&dev_priv->irq_lock); > +} > + > static void gen6_enable_rps_interrupts(struct drm_device *dev) > { > struct drm_i915_private *dev_priv = dev->dev_private; > @@ -3446,7 +3480,7 @@ static void gen8_enable_rps(struct drm_device *dev) > > gen6_set_rps(dev, (I915_READ(GEN6_GT_PERF_STATUS) & 0xff00) >> 8); > > - gen6_enable_rps_interrupts(dev); > + gen8_enable_rps_interrupts(dev); > > gen6_gt_force_wake_put(dev_priv, FORCEWAKE_ALL); > } > -- > 1.9.1 > > _______________________________________________ > Intel-gfx mailing list > Intel-gfx@lists.freedesktop.org > http://lists.freedesktop.org/mailman/listinfo/intel-gfx
diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 2d76183..6af51ad 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -248,6 +248,49 @@ static bool ivb_can_enable_err_int(struct drm_device *dev) return true; } +/** + * bdw_update_pm_irq - update GT interrupt 2 + * @dev_priv: driver private + * @interrupt_mask: mask of interrupt bits to update + * @enabled_irq_mask: mask of interrupt bits to enable + * + * Copied from the snb function, updated with relevant register offsets + */ +static void bdw_update_pm_irq(struct drm_i915_private *dev_priv, + uint32_t interrupt_mask, + uint32_t enabled_irq_mask) +{ + uint32_t new_val; + + assert_spin_locked(&dev_priv->irq_lock); + + if (dev_priv->pm.irqs_disabled) { + WARN(1, "IRQs disabled\n"); + return; + } + + new_val = dev_priv->pm_irq_mask; + new_val &= ~interrupt_mask; + new_val |= (~enabled_irq_mask & interrupt_mask); + + if (new_val != dev_priv->pm_irq_mask) { + dev_priv->pm_irq_mask = new_val; + I915_WRITE(GEN8_GT_IMR(2), I915_READ(GEN8_GT_IMR(2)) | + dev_priv->pm_irq_mask); + POSTING_READ(GEN8_GT_IMR(2)); + } +} + +void bdw_enable_pm_irq(struct drm_i915_private *dev_priv, uint32_t mask) +{ + bdw_update_pm_irq(dev_priv, mask, mask); +} + +void bdw_disable_pm_irq(struct drm_i915_private *dev_priv, uint32_t mask) +{ + bdw_update_pm_irq(dev_priv, mask, 0); +} + static bool cpt_can_enable_serr_int(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; @@ -1098,8 +1141,12 @@ static void gen6_pm_rps_work(struct work_struct *work) spin_lock_irq(&dev_priv->irq_lock); pm_iir = dev_priv->rps.pm_iir; dev_priv->rps.pm_iir = 0; - /* Make sure not to corrupt PMIMR state used by ringbuffer code */ - snb_enable_pm_irq(dev_priv, dev_priv->pm_rps_events); + if (IS_BROADWELL(dev_priv->dev)) + bdw_enable_pm_irq(dev_priv, dev_priv->pm_rps_events); + else { + /* Make sure not to corrupt PMIMR state used by ringbuffer */ + snb_enable_pm_irq(dev_priv, dev_priv->pm_rps_events); + } spin_unlock_irq(&dev_priv->irq_lock); /* Make sure we didn't queue anything we're not going to process. */ @@ -1296,6 +1343,19 @@ static void snb_gt_irq_handler(struct drm_device *dev, ivybridge_parity_error_irq_handler(dev, gt_iir); } +static void gen8_rps_irq_handler(struct drm_i915_private *dev_priv, u32 pm_iir) +{ + if ((pm_iir & dev_priv->pm_rps_events) == 0) + return; + + spin_lock(&dev_priv->irq_lock); + dev_priv->rps.pm_iir |= pm_iir & dev_priv->pm_rps_events; + bdw_disable_pm_irq(dev_priv, pm_iir & dev_priv->pm_rps_events); + spin_unlock(&dev_priv->irq_lock); + + queue_work(dev_priv->wq, &dev_priv->rps.work); +} + static irqreturn_t gen8_gt_irq_handler(struct drm_device *dev, struct drm_i915_private *dev_priv, u32 master_ctl) @@ -1334,6 +1394,17 @@ static irqreturn_t gen8_gt_irq_handler(struct drm_device *dev, DRM_ERROR("The master control interrupt lied (GT1)!\n"); } + if (master_ctl & GEN8_GT_PM_IRQ) { + tmp = I915_READ(GEN8_GT_IIR(2)); + if (tmp & dev_priv->pm_rps_events) { + ret = IRQ_HANDLED; + gen8_rps_irq_handler(dev_priv, tmp); + I915_WRITE(GEN8_GT_IIR(2), + tmp & dev_priv->pm_rps_events); + } else + DRM_ERROR("The master control interrupt lied (PM)!\n"); + } + if (master_ctl & GEN8_GT_VECS_IRQ) { tmp = I915_READ(GEN8_GT_IIR(3)); if (tmp) { diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 0eff337..ca4f8b9 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -4194,6 +4194,7 @@ enum punit_power_well { #define GEN8_DE_PIPE_A_IRQ (1<<16) #define GEN8_DE_PIPE_IRQ(pipe) (1<<(16+pipe)) #define GEN8_GT_VECS_IRQ (1<<6) +#define GEN8_GT_PM_IRQ (1<<4) #define GEN8_GT_VCS2_IRQ (1<<3) #define GEN8_GT_VCS1_IRQ (1<<2) #define GEN8_GT_BCS_IRQ (1<<1) diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index d8b540b..d560a9b 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -653,6 +653,8 @@ void ilk_enable_gt_irq(struct drm_i915_private *dev_priv, uint32_t mask); void ilk_disable_gt_irq(struct drm_i915_private *dev_priv, uint32_t mask); void snb_enable_pm_irq(struct drm_i915_private *dev_priv, uint32_t mask); void snb_disable_pm_irq(struct drm_i915_private *dev_priv, uint32_t mask); +void bdw_enable_pm_irq(struct drm_i915_private *dev_priv, uint32_t mask); +void bdw_disable_pm_irq(struct drm_i915_private *dev_priv, uint32_t mask); void intel_runtime_pm_disable_interrupts(struct drm_device *dev); void intel_runtime_pm_restore_interrupts(struct drm_device *dev); int intel_get_crtc_scanline(struct intel_crtc *crtc); diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 834c49c..0e69c97 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -3246,6 +3246,26 @@ void valleyview_set_rps(struct drm_device *dev, u8 val) trace_intel_gpu_freq_change(vlv_gpu_freq(dev_priv, val)); } +static void gen8_disable_rps_interrupts(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + + I915_WRITE(GEN6_PMINTRMSK, 0xffffffff); + I915_WRITE(GEN8_GT_IER(2), I915_READ(GEN8_GT_IER(2)) & + ~dev_priv->pm_rps_events); + /* Complete PM interrupt masking here doesn't race with the rps work + * item again unmasking PM interrupts because that is using a different + * register (GEN8_GT_IMR(2)) to mask PM interrupts. The only risk is in + * leaving stale bits in GEN8_GT_IIR(2) and GEN8_GT_IMR(2) which + * gen8_enable_rps will clean up. */ + + spin_lock_irq(&dev_priv->irq_lock); + dev_priv->rps.pm_iir = 0; + spin_unlock_irq(&dev_priv->irq_lock); + + I915_WRITE(GEN8_GT_IIR(2), dev_priv->pm_rps_events); +} + static void gen6_disable_rps_interrupts(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; @@ -3272,7 +3292,10 @@ static void gen6_disable_rps(struct drm_device *dev) I915_WRITE(GEN6_RC_CONTROL, 0); I915_WRITE(GEN6_RPNSWREQ, 1 << 31); - gen6_disable_rps_interrupts(dev); + if (IS_BROADWELL(dev)) + gen8_disable_rps_interrupts(dev); + else + gen6_disable_rps_interrupts(dev); } static void valleyview_disable_rps(struct drm_device *dev) @@ -3344,6 +3367,17 @@ int intel_enable_rc6(const struct drm_device *dev) return i915.enable_rc6; } +static void gen8_enable_rps_interrupts(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + + spin_lock_irq(&dev_priv->irq_lock); + WARN_ON(dev_priv->rps.pm_iir); + bdw_enable_pm_irq(dev_priv, dev_priv->pm_rps_events); + I915_WRITE(GEN8_GT_IIR(2), dev_priv->pm_rps_events); + spin_unlock_irq(&dev_priv->irq_lock); +} + static void gen6_enable_rps_interrupts(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; @@ -3446,7 +3480,7 @@ static void gen8_enable_rps(struct drm_device *dev) gen6_set_rps(dev, (I915_READ(GEN6_GT_PERF_STATUS) & 0xff00) >> 8); - gen6_enable_rps_interrupts(dev); + gen8_enable_rps_interrupts(dev); gen6_gt_force_wake_put(dev_priv, FORCEWAKE_ALL); }