Message ID | 1383451680-11173-12-git-send-email-benjamin.widawsky@intel.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
On Sat, Nov 02, 2013 at 09:07:09PM -0700, Ben Widawsky wrote: > The interrupt handling implementation remains the same as previous > generations with the 4 types of registers, status, identity, mask, and > enable. However the layout of where the bits go have changed entirely. > To address these changes, all of the interrupt vfuncs needed special > gen8 code. > > The way it works is there is a top level status register now which > informs the interrupt service routine which unit caused the interrupt, > and therefore which interrupt registers to read to process the > interrupt. For display the division is quite logical, a set of interrupt > registers for each pipe, and in addition to those, a set each for "misc" > and port. > > For GT the things get a bit hairy, as seen by the code. Each of the GT > units has it's own bits defined. They all look *very similar* and > resides in 16 bits of a GT register. As an example, RCS and BCS share > register 0. To compact the code a bit, at a slight expense to > complexity, this is exactly how the code works as well. 2 structures are > added to the ring buffer so that our ring buffer interrupt handling code > knows which ring shares the interrupt registers, and a shift value (ie. > the top or bottom 16 bits of the register). > > The above allows us to kept the interrupt register caching scheme, the > per interrupt enables, and the code to mask and unmask interrupts > relatively clean (again at the cost of some more complexity). > > Most of the GT units mentioned above are command streamers, and so the > symmetry should work quite well for even the yet to be implemented rings > which Broadwell adds. > > v2: Fixes up a couple of bugs, and is more verbose about errors in the > Broadwell interrupt handler. > > v3: fix DE_MISC IER offset > > v4: Simplify interrupts: > I totally misread the docs the first time I implemented interrupts, and > so this should greatly simplify the mess. Unlike GEN6, we never touch > the regular mask registers in irq_get/put. > > v5: Rebased on to of recent pch hotplug setup changes. > > v6: Fixup on top of moving num_pipes to intel_info. > > v7: Rebased on top of Egbert Eich's hpd irq handling rework. Also > wired up ibx_hpd_irq_setup for gen8. > > v8: Rebase on top of Jani's asle handling rework. > > v9: Rebase on top of Ben's VECS enabling for Haswell, where he > unfortunately went OCD on the gt irq #defines. Not that they're still > not yet fully consistent: > - Used the GT_RENDER_ #defines + bdw shifts. > - Dropped the shift from the L3_PARITY stuff, seemed clearer. > - s/irq_refcount/irq_refcount.gt/ > > v10: Squash in VECS enabling patches and the gen8_gt_irq_handler > refactoring from Zhao Yakui <yakui.zhao@intel.com> > > v11: Rebase on top of the interrupt cleanups in upstream. > > v12: Rebase on top of Ben's DPF changes in upstream. > > v13: Drop bdw from the HAS_L3_DPF feature flag for now, it's unclear what > exactly needs to be done. Requested by Ben. > > Signed-off-by: Ben Widawsky <ben@bwidawsk.net> (v4) > Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch> I've had to fix quite a few things here, and I've made myself a todo for patches to write on top of this one here. See the v14 changelog entry. -Daniel > --- > drivers/gpu/drm/i915/i915_drv.h | 5 +- > drivers/gpu/drm/i915/i915_irq.c | 327 ++++++++++++++++++++++++++++++++ > drivers/gpu/drm/i915/i915_reg.h | 63 ++++++ > drivers/gpu/drm/i915/intel_ringbuffer.c | 90 +++++++-- > 4 files changed, 473 insertions(+), 12 deletions(-) > > diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h > index c1b178a..83d016c 100644 > --- a/drivers/gpu/drm/i915/i915_drv.h > +++ b/drivers/gpu/drm/i915/i915_drv.h > @@ -1315,7 +1315,10 @@ typedef struct drm_i915_private { > struct mutex dpio_lock; > > /** Cached value of IMR to avoid reads in updating the bitfield */ > - u32 irq_mask; > + union { > + u32 irq_mask; > + u32 de_irq_mask[I915_MAX_PIPES]; > + }; > u32 gt_irq_mask; > u32 pm_irq_mask; > > diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c > index a9f0cb6..3f0c9e3 100644 > --- a/drivers/gpu/drm/i915/i915_irq.c > +++ b/drivers/gpu/drm/i915/i915_irq.c > @@ -1118,6 +1118,56 @@ static void snb_gt_irq_handler(struct drm_device *dev, > ivybridge_parity_error_irq_handler(dev, gt_iir); > } > > +static irqreturn_t gen8_gt_irq_handler(struct drm_device *dev, > + struct drm_i915_private *dev_priv, > + u32 master_ctl) > +{ > + u32 rcs, bcs, vcs; > + uint32_t tmp = 0; > + irqreturn_t ret = IRQ_NONE; > + > + if (master_ctl & (GEN8_GT_RCS_IRQ | GEN8_GT_BCS_IRQ)) { > + tmp = I915_READ(GEN8_GT_IIR(0)); > + if (tmp) { > + ret = IRQ_HANDLED; > + rcs = tmp >> GEN8_RCS_IRQ_SHIFT; > + bcs = tmp >> GEN8_BCS_IRQ_SHIFT; > + if (rcs & GT_RENDER_USER_INTERRUPT) > + notify_ring(dev, &dev_priv->ring[RCS]); > + if (bcs & GT_RENDER_USER_INTERRUPT) > + notify_ring(dev, &dev_priv->ring[BCS]); > + I915_WRITE(GEN8_GT_IIR(0), tmp); > + } else > + DRM_ERROR("The master control interrupt lied (GT0)!\n"); > + } > + > + if (master_ctl & GEN8_GT_VCS1_IRQ) { > + tmp = I915_READ(GEN8_GT_IIR(1)); > + if (tmp) { > + ret = IRQ_HANDLED; > + vcs = tmp >> GEN8_VCS1_IRQ_SHIFT; > + if (vcs & GT_RENDER_USER_INTERRUPT) > + notify_ring(dev, &dev_priv->ring[VCS]); > + I915_WRITE(GEN8_GT_IIR(1), tmp); > + } else > + DRM_ERROR("The master control interrupt lied (GT1)!\n"); > + } > + > + if (master_ctl & GEN8_GT_VECS_IRQ) { > + tmp = I915_READ(GEN8_GT_IIR(3)); > + if (tmp) { > + ret = IRQ_HANDLED; > + vcs = tmp >> GEN8_VECS_IRQ_SHIFT; > + if (vcs & GT_RENDER_USER_INTERRUPT) > + notify_ring(dev, &dev_priv->ring[VECS]); > + I915_WRITE(GEN8_GT_IIR(3), tmp); > + } else > + DRM_ERROR("The master control interrupt lied (GT3)!\n"); > + } > + > + return ret; > +} > + > #define HPD_STORM_DETECT_PERIOD 1000 > #define HPD_STORM_THRESHOLD 5 > > @@ -1699,6 +1749,85 @@ static irqreturn_t ironlake_irq_handler(int irq, void *arg) > return ret; > } > > +static irqreturn_t gen8_irq_handler(int irq, void *arg) > +{ > + struct drm_device *dev = arg; > + struct drm_i915_private *dev_priv = dev->dev_private; > + u32 master_ctl; > + irqreturn_t ret = IRQ_NONE; > + uint32_t tmp = 0; > + > + atomic_inc(&dev_priv->irq_received); > + > + master_ctl = I915_READ(GEN8_MASTER_IRQ); > + master_ctl &= ~DE_MASTER_IRQ_CONTROL; > + if (!master_ctl) > + return IRQ_NONE; > + > + if ((master_ctl & ~GEN8_RSVD_IRQS) == 0) { > + DRM_ERROR("Only received RSVD IRQs 0x%08x\n", master_ctl); > + return IRQ_NONE; > + } > + > + I915_WRITE(GEN8_MASTER_IRQ, 0); > + > + /* NB: Posting read isn't necessary here because we're required to do > + * another read no matter what > + POSTING_READ(GEN8_MASTER_IRQ); > + */ > + > + ret = gen8_gt_irq_handler(dev, dev_priv, master_ctl); > + > + if (master_ctl & GEN8_DE_MISC_IRQ) { > + tmp = I915_READ(GEN8_DE_MISC_IIR); > + if (tmp) { > + I915_WRITE(GEN8_DE_MISC_IIR, tmp); > + ret = IRQ_HANDLED; > + } > + > + if (tmp & GEN8_DE_MISC_GSE) > + intel_opregion_asle_intr(dev); > + else if (tmp) > + DRM_ERROR("Unexpected DE Misc interrupt\n"); > + else > + DRM_ERROR("The master control interrupt lied (DE MISC)!\n"); > + > + } > + > + if (master_ctl & GEN8_DE_IRQS) { > + int de_ret = 0; > + int pipe; > + for_each_pipe(pipe) { > + uint32_t pipe_iir; > + > + pipe_iir = I915_READ(GEN8_DE_PIPE_IIR(pipe)); > + if (pipe_iir & _PIPE_VBLANK) { > + drm_handle_vblank(dev, pipe); > + } > + if (pipe_iir & _PIPE_FLIP_DONE) { > + intel_prepare_page_flip(dev, pipe); > + intel_finish_page_flip_plane(dev, pipe); > + } > + > + if (pipe_iir & GEN8_DE_PIPE_IRQ_ERRORS) > + DRM_ERROR("Errors on pipe %c\n", 'A' + pipe); > + > + if (pipe_iir) { > + de_ret++; > + ret = IRQ_HANDLED; > + I915_WRITE(GEN8_DE_PIPE_IIR(pipe), pipe_iir); > + } > + } > + if (!de_ret) > + DRM_ERROR("The master control interrupt lied (DE PIPE)!\n"); > + } > + > + I915_WRITE(GEN8_MASTER_IRQ, DE_MASTER_IRQ_CONTROL); > + POSTING_READ(GEN8_MASTER_IRQ); > + > + return ret; > +} > + > static void i915_error_wake_up(struct drm_i915_private *dev_priv, > bool reset_completed) > { > @@ -2052,6 +2181,25 @@ static int valleyview_enable_vblank(struct drm_device *dev, int pipe) > return 0; > } > > +static int gen8_enable_vblank(struct drm_device *dev, int pipe) > +{ > + struct drm_i915_private *dev_priv = dev->dev_private; > + unsigned long irqflags; > + uint32_t imr; > + > + if (!i915_pipe_enabled(dev, pipe)) > + return -EINVAL; > + > + spin_lock_irqsave(&dev_priv->irq_lock, irqflags); > + imr = I915_READ(GEN8_DE_PIPE_IMR(pipe)); > + if ((imr & _PIPE_VBLANK) == 1) { > + I915_WRITE(GEN8_DE_PIPE_IMR(pipe), imr & ~_PIPE_VBLANK); > + POSTING_READ(GEN8_DE_PIPE_IMR(pipe)); > + } > + spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags); > + return 0; > +} > + > /* Called from drm generic code, passed 'crtc' which > * we use as a pipe index > */ > @@ -2100,6 +2248,24 @@ static void valleyview_disable_vblank(struct drm_device *dev, int pipe) > spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags); > } > > +static void gen8_disable_vblank(struct drm_device *dev, int pipe) > +{ > + struct drm_i915_private *dev_priv = dev->dev_private; > + unsigned long irqflags; > + uint32_t imr; > + > + if (!i915_pipe_enabled(dev, pipe)) > + return; > + > + spin_lock_irqsave(&dev_priv->irq_lock, irqflags); > + imr = I915_READ(GEN8_DE_PIPE_IMR(pipe)); > + if ((imr & _PIPE_VBLANK) == 0) { > + I915_WRITE(GEN8_DE_PIPE_IMR(pipe), imr | _PIPE_VBLANK); > + POSTING_READ(GEN8_DE_PIPE_IMR(pipe)); > + } > + spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags); > +} > + > static u32 > ring_last_seqno(struct intel_ring_buffer *ring) > { > @@ -2430,6 +2596,51 @@ static void valleyview_irq_preinstall(struct drm_device *dev) > POSTING_READ(VLV_IER); > } > > +static void gen8_irq_preinstall(struct drm_device *dev) > +{ > + struct drm_i915_private *dev_priv = dev->dev_private; > + int pipe; > + > + atomic_set(&dev_priv->irq_received, 0); > + > + I915_WRITE(GEN8_MASTER_IRQ, 0); > + POSTING_READ(GEN8_MASTER_IRQ); > + > + /* IIR can theoretically queue up two events. Be paranoid */ > +#define GEN8_IRQ_INIT_NDX(type, which) \ > + I915_WRITE(GEN8_##type##_IMR(which), 0xffffffff); \ > + POSTING_READ(GEN8_##type##_IMR(which)); \ > + I915_WRITE(GEN8_##type##_IER(which), 0); \ > + I915_WRITE(GEN8_##type##_IIR(which), 0xffffffff); \ > + POSTING_READ(GEN8_##type##_IIR(which)); \ > + I915_WRITE(GEN8_##type##_IIR(which), 0xffffffff) > + > +#define GEN8_IRQ_INIT(type) \ > + I915_WRITE(GEN8_##type##_IMR, 0xffffffff); \ > + POSTING_READ(GEN8_##type##_IMR); \ > + I915_WRITE(GEN8_##type##_IER, 0); \ > + I915_WRITE(GEN8_##type##_IIR, 0xffffffff); \ > + POSTING_READ(GEN8_##type##_IIR); \ > + I915_WRITE(GEN8_##type##_IIR, 0xffffffff) > + > + GEN8_IRQ_INIT_NDX(GT, 0); > + GEN8_IRQ_INIT_NDX(GT, 1); > + GEN8_IRQ_INIT_NDX(GT, 2); > + GEN8_IRQ_INIT_NDX(GT, 3); > + > + for_each_pipe(pipe) { > + GEN8_IRQ_INIT_NDX(DE_PIPE, pipe); > + } > + > + GEN8_IRQ_INIT(DE_PORT); > + GEN8_IRQ_INIT(DE_MISC); > + GEN8_IRQ_INIT(PCU); > +#undef GEN8_IRQ_INIT > +#undef GEN8_IRQ_INIT_NDX > + > + POSTING_READ(GEN8_PCU_IIR); > +} > + > static void ibx_hpd_irq_setup(struct drm_device *dev) > { > drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; > @@ -2635,6 +2846,114 @@ static int valleyview_irq_postinstall(struct drm_device *dev) > return 0; > } > > +static void gen8_gt_irq_postinstall(struct drm_i915_private *dev_priv) > +{ > + int i; > + > + /* These are interrupts we'll toggle with the ring mask register */ > + uint32_t gt_interrupts[] = { > + GT_RENDER_USER_INTERRUPT << GEN8_RCS_IRQ_SHIFT | > + GT_RENDER_L3_PARITY_ERROR_INTERRUPT | > + GT_RENDER_USER_INTERRUPT << GEN8_BCS_IRQ_SHIFT, > + GT_RENDER_USER_INTERRUPT << GEN8_VCS1_IRQ_SHIFT | > + GT_RENDER_USER_INTERRUPT << GEN8_VCS2_IRQ_SHIFT, > + 0, > + GT_RENDER_USER_INTERRUPT << GEN8_VECS_IRQ_SHIFT > + }; > + > + for (i = 0; i < ARRAY_SIZE(gt_interrupts); i++) { > + u32 tmp = I915_READ(GEN8_GT_IIR(i)); > + if (tmp) > + DRM_ERROR("Interrupt (%d) should have been masked in pre-install 0x%08x\n", > + i, tmp); > + I915_WRITE(GEN8_GT_IMR(i), ~gt_interrupts[i]); > + I915_WRITE(GEN8_GT_IER(i), gt_interrupts[i]); > + } > + POSTING_READ(GEN8_GT_IER(0)); > +} > + > +static void gen8_de_irq_postinstall(struct drm_i915_private *dev_priv) > +{ > + struct drm_device *dev = dev_priv->dev; > + uint32_t de_pipe_enables = _PIPE_FLIP_DONE | > + _PIPE_SCAN_LINE_EVENT | > + _PIPE_VBLANK | > + GEN8_DE_PIPE_IRQ_ERRORS; > + int pipe; > + dev_priv->de_irq_mask[PIPE_A] = ~de_pipe_enables; > + dev_priv->de_irq_mask[PIPE_B] = ~de_pipe_enables; > + dev_priv->de_irq_mask[PIPE_C] = ~de_pipe_enables; > + > + for_each_pipe(pipe) { > + u32 tmp = I915_READ(GEN8_DE_PIPE_IIR(pipe)); > + if (tmp) > + DRM_ERROR("Interrupt (%d) should have been masked in pre-install 0x%08x\n", > + pipe, tmp); > + I915_WRITE(GEN8_DE_PIPE_IMR(pipe), dev_priv->de_irq_mask[pipe]); > + I915_WRITE(GEN8_DE_PIPE_IER(pipe), de_pipe_enables); > + } > + POSTING_READ(GEN8_DE_PIPE_ISR(0)); > + > + I915_WRITE(GEN8_DE_PORT_IMR, ~_PORT_DP_A_HOTPLUG); > + I915_WRITE(GEN8_DE_PORT_IER, _PORT_DP_A_HOTPLUG); > + POSTING_READ(GEN8_DE_PORT_IER); > +} > + > +static int gen8_irq_postinstall(struct drm_device *dev) > +{ > + struct drm_i915_private *dev_priv = dev->dev_private; > + > + gen8_gt_irq_postinstall(dev_priv); > + gen8_de_irq_postinstall(dev_priv); > + > + ibx_irq_postinstall(dev); > + > + I915_WRITE(GEN8_MASTER_IRQ, DE_MASTER_IRQ_CONTROL); > + POSTING_READ(GEN8_MASTER_IRQ); > + > + return 0; > +} > + > +static void gen8_irq_uninstall(struct drm_device *dev) > +{ > + struct drm_i915_private *dev_priv = dev->dev_private; > + int pipe; > + > + if (!dev_priv) > + return; > + > + atomic_set(&dev_priv->irq_received, 0); > + > + I915_WRITE(GEN8_MASTER_IRQ, 0); > + > +#define GEN8_IRQ_FINI_NDX(type, which) \ > + I915_WRITE(GEN8_##type##_IMR(which), 0xffffffff); \ > + I915_WRITE(GEN8_##type##_IER(which), 0); \ > + I915_WRITE(GEN8_##type##_IIR(which), 0xffffffff) > + > +#define GEN8_IRQ_FINI(type) \ > + I915_WRITE(GEN8_##type##_IMR, 0xffffffff); \ > + I915_WRITE(GEN8_##type##_IER, 0); \ > + I915_WRITE(GEN8_##type##_IIR, 0xffffffff) > + > + GEN8_IRQ_FINI_NDX(GT, 0); > + GEN8_IRQ_FINI_NDX(GT, 1); > + GEN8_IRQ_FINI_NDX(GT, 2); > + GEN8_IRQ_FINI_NDX(GT, 3); > + > + for_each_pipe(pipe) { > + GEN8_IRQ_FINI_NDX(DE_PIPE, pipe); > + } > + > + GEN8_IRQ_FINI(DE_PORT); > + GEN8_IRQ_FINI(DE_MISC); > + GEN8_IRQ_FINI(PCU); > +#undef GEN8_IRQ_FINI > +#undef GEN8_IRQ_FINI_NDX > + > + POSTING_READ(GEN8_PCU_IIR); > +} > + > static void valleyview_irq_uninstall(struct drm_device *dev) > { > drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; > @@ -3414,6 +3733,14 @@ void intel_irq_init(struct drm_device *dev) > dev->driver->enable_vblank = valleyview_enable_vblank; > dev->driver->disable_vblank = valleyview_disable_vblank; > dev_priv->display.hpd_irq_setup = i915_hpd_irq_setup; > + } else if (IS_GEN8(dev)) { > + dev->driver->irq_handler = gen8_irq_handler; > + dev->driver->irq_preinstall = gen8_irq_preinstall; > + dev->driver->irq_postinstall = gen8_irq_postinstall; > + dev->driver->irq_uninstall = gen8_irq_uninstall; > + dev->driver->enable_vblank = gen8_enable_vblank; > + dev->driver->disable_vblank = gen8_disable_vblank; > + dev_priv->display.hpd_irq_setup = ibx_hpd_irq_setup; > } else if (HAS_PCH_SPLIT(dev)) { > dev->driver->irq_handler = ironlake_irq_handler; > dev->driver->irq_preinstall = ironlake_irq_preinstall; > diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h > index fb6ad89..b801b88 100644 > --- a/drivers/gpu/drm/i915/i915_reg.h > +++ b/drivers/gpu/drm/i915/i915_reg.h > @@ -3989,6 +3989,69 @@ > #define GTIIR 0x44018 > #define GTIER 0x4401c > > +#define GEN8_MASTER_IRQ 0x44200 > +#define GEN8_PCU_IRQ (1<<30) > +#define GEN8_DE_PCH_IRQ (1<<23) > +#define GEN8_DE_MISC_IRQ (1<<22) > +#define GEN8_DE_PORT_IRQ (1<<20) > +#define GEN8_DE_PIPE_C_IRQ (1<<18) > +#define GEN8_DE_PIPE_B_IRQ (1<<17) > +#define GEN8_DE_PIPE_A_IRQ (1<<16) > +#define GEN8_GT_VECS_IRQ (1<<6) > +#define GEN8_GT_VCS2_IRQ (1<<3) > +#define GEN8_GT_VCS1_IRQ (1<<2) > +#define GEN8_GT_BCS_IRQ (1<<1) > +#define GEN8_GT_RCS_IRQ (1<<0) > +/* Lazy definition */ > +#define GEN8_GT_IRQS 0x000000ff > +#define GEN8_DE_IRQS 0x01ff0000 > +#define GEN8_RSVD_IRQS 0xB700ff00 > + > +#define GEN8_GT_ISR(which) (0x44300 + (0x10 * (which))) > +#define GEN8_GT_IMR(which) (0x44304 + (0x10 * (which))) > +#define GEN8_GT_IIR(which) (0x44308 + (0x10 * (which))) > +#define GEN8_GT_IER(which) (0x4430c + (0x10 * (which))) > + > +#define GEN8_BCS_IRQ_SHIFT 16 > +#define GEN8_RCS_IRQ_SHIFT 0 > +#define GEN8_VCS2_IRQ_SHIFT 16 > +#define GEN8_VCS1_IRQ_SHIFT 0 > +#define GEN8_VECS_IRQ_SHIFT 0 > + > +#define GEN8_DE_PIPE_ISR(pipe) (0x44400 + (0x10 * (pipe))) > +#define GEN8_DE_PIPE_IMR(pipe) (0x44404 + (0x10 * (pipe))) > +#define GEN8_DE_PIPE_IIR(pipe) (0x44408 + (0x10 * (pipe))) > +#define GEN8_DE_PIPE_IER(pipe) (0x4440c + (0x10 * (pipe))) > +#define _PIPE_UNDERRUN (1 << 31) > +#define _PIPE_CDCLK_CRC_ERROR (1 << 29) > +#define _PIPE_CURSOR_FAULT (1 << 10) > +#define _PIPE_SPRITE_FAULT (1 << 9) > +#define _PIPE_PRIMARY_FAULT (1 << 8) > +#define _PIPE_SPRITE_FLIP_DONE (1 << 5) > +#define _PIPE_FLIP_DONE (1 << 4) > +#define _PIPE_SCAN_LINE_EVENT (1 << 3) > +#define _PIPE_VBLANK (1 << 0) > +#define GEN8_DE_PIPE_IRQ_ERRORS (_PIPE_UNDERRUN | _PIPE_CDCLK_CRC_ERROR | \ > + _PIPE_CURSOR_FAULT | _PIPE_SPRITE_FAULT | \ > + _PIPE_PRIMARY_FAULT) > + > +#define GEN8_DE_PORT_ISR 0x44440 > +#define GEN8_DE_PORT_IMR 0x44444 > +#define GEN8_DE_PORT_IIR 0x44448 > +#define GEN8_DE_PORT_IER 0x4444c > +#define _PORT_DP_A_HOTPLUG (1 << 3) > + > +#define GEN8_DE_MISC_ISR 0x44460 > +#define GEN8_DE_MISC_IMR 0x44464 > +#define GEN8_DE_MISC_IIR 0x44468 > +#define GEN8_DE_MISC_IER 0x4446c > +#define GEN8_DE_MISC_GSE (1 << 27) > + > +#define GEN8_PCU_ISR 0x444e0 > +#define GEN8_PCU_IMR 0x444e4 > +#define GEN8_PCU_IIR 0x444e8 > +#define GEN8_PCU_IER 0x444ec > + > #define ILK_DISPLAY_CHICKEN2 0x42004 > /* Required on all Ironlake and Sandybridge according to the B-Spec. */ > #define ILK_ELPIN_409_SELECT (1 << 25) > diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c > index 2dec134..b2161f2 100644 > --- a/drivers/gpu/drm/i915/intel_ringbuffer.c > +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c > @@ -1066,6 +1066,48 @@ hsw_vebox_put_irq(struct intel_ring_buffer *ring) > spin_unlock_irqrestore(&dev_priv->irq_lock, flags); > } > > +static bool > +gen8_ring_get_irq(struct intel_ring_buffer *ring) > +{ > + struct drm_device *dev = ring->dev; > + struct drm_i915_private *dev_priv = dev->dev_private; > + unsigned long flags; > + > + if (!dev->irq_enabled) > + return false; > + > + spin_lock_irqsave(&dev_priv->irq_lock, flags); > + if (ring->irq_refcount++ == 0) { > + if (HAS_L3_DPF(dev) && ring->id == RCS) > + I915_WRITE_IMR(ring, ~(ring->irq_enable_mask | > + GT_RENDER_L3_PARITY_ERROR_INTERRUPT)); > + else > + I915_WRITE_IMR(ring, ~ring->irq_enable_mask); > + POSTING_READ(RING_IMR(ring->mmio_base)); > + } > + spin_unlock_irqrestore(&dev_priv->irq_lock, flags); > + > + return true; > +} > + > +static void > +gen8_ring_put_irq(struct intel_ring_buffer *ring) > +{ > + struct drm_device *dev = ring->dev; > + drm_i915_private_t *dev_priv = dev->dev_private; > + unsigned long flags; > + > + spin_lock_irqsave(&dev_priv->irq_lock, flags); > + if (--ring->irq_refcount == 0) { > + if (HAS_L3_DPF(dev) && ring->id == RCS) > + I915_WRITE_IMR(ring, ~GT_RENDER_L3_PARITY_ERROR_INTERRUPT); > + else > + I915_WRITE_IMR(ring, ~0); > + POSTING_READ(RING_IMR(ring->mmio_base)); > + } > + spin_unlock_irqrestore(&dev_priv->irq_lock, flags); > +} > + > static int > i965_dispatch_execbuffer(struct intel_ring_buffer *ring, > u32 offset, u32 length, > @@ -1732,8 +1774,13 @@ int intel_init_render_ring_buffer(struct drm_device *dev) > ring->flush = gen7_render_ring_flush; > if (INTEL_INFO(dev)->gen == 6) > ring->flush = gen6_render_ring_flush; > - ring->irq_get = gen6_ring_get_irq; > - ring->irq_put = gen6_ring_put_irq; > + if (INTEL_INFO(dev)->gen >= 8) { > + ring->irq_get = gen8_ring_get_irq; > + ring->irq_put = gen8_ring_put_irq; > + } else { > + ring->irq_get = gen6_ring_get_irq; > + ring->irq_put = gen6_ring_put_irq; > + } > ring->irq_enable_mask = GT_RENDER_USER_INTERRUPT; > ring->get_seqno = gen6_ring_get_seqno; > ring->set_seqno = ring_set_seqno; > @@ -1897,9 +1944,15 @@ int intel_init_bsd_ring_buffer(struct drm_device *dev) > ring->add_request = gen6_add_request; > ring->get_seqno = gen6_ring_get_seqno; > ring->set_seqno = ring_set_seqno; > - ring->irq_enable_mask = GT_BSD_USER_INTERRUPT; > - ring->irq_get = gen6_ring_get_irq; > - ring->irq_put = gen6_ring_put_irq; > + if (INTEL_INFO(dev)->gen >= 8) { > + ring->irq_enable_mask = GT_RENDER_USER_INTERRUPT << GEN8_VCS1_IRQ_SHIFT; > + ring->irq_get = gen8_ring_get_irq; > + ring->irq_put = gen8_ring_put_irq; > + } else { > + ring->irq_enable_mask = GT_BSD_USER_INTERRUPT; > + ring->irq_get = gen6_ring_get_irq; > + ring->irq_put = gen6_ring_put_irq; > + } > ring->dispatch_execbuffer = gen6_ring_dispatch_execbuffer; > ring->sync_to = gen6_ring_sync; > ring->semaphore_register[RCS] = MI_SEMAPHORE_SYNC_VR; > @@ -1946,9 +1999,15 @@ int intel_init_blt_ring_buffer(struct drm_device *dev) > ring->add_request = gen6_add_request; > ring->get_seqno = gen6_ring_get_seqno; > ring->set_seqno = ring_set_seqno; > - ring->irq_enable_mask = GT_BLT_USER_INTERRUPT; > - ring->irq_get = gen6_ring_get_irq; > - ring->irq_put = gen6_ring_put_irq; > + if (INTEL_INFO(dev)->gen >= 8) { > + ring->irq_enable_mask = GT_RENDER_USER_INTERRUPT << GEN8_BCS_IRQ_SHIFT; > + ring->irq_get = gen8_ring_get_irq; > + ring->irq_put = gen8_ring_put_irq; > + } else { > + ring->irq_enable_mask = GT_BLT_USER_INTERRUPT; > + ring->irq_get = gen6_ring_get_irq; > + ring->irq_put = gen6_ring_put_irq; > + } > ring->dispatch_execbuffer = gen6_ring_dispatch_execbuffer; > ring->sync_to = gen6_ring_sync; > ring->semaphore_register[RCS] = MI_SEMAPHORE_SYNC_BR; > @@ -1978,10 +2037,19 @@ int intel_init_vebox_ring_buffer(struct drm_device *dev) > ring->add_request = gen6_add_request; > ring->get_seqno = gen6_ring_get_seqno; > ring->set_seqno = ring_set_seqno; > - ring->irq_enable_mask = PM_VEBOX_USER_INTERRUPT; > - ring->irq_get = hsw_vebox_get_irq; > - ring->irq_put = hsw_vebox_put_irq; > ring->dispatch_execbuffer = gen6_ring_dispatch_execbuffer; > + > + if (INTEL_INFO(dev)->gen >= 8) { > + ring->irq_enable_mask = > + (GT_RENDER_USER_INTERRUPT << GEN8_VECS_IRQ_SHIFT) | > + GT_RENDER_CS_MASTER_ERROR_INTERRUPT; > + ring->irq_get = gen8_ring_get_irq; > + ring->irq_put = gen8_ring_put_irq; > + } else { > + ring->irq_enable_mask = PM_VEBOX_USER_INTERRUPT; > + ring->irq_get = hsw_vebox_get_irq; > + ring->irq_put = hsw_vebox_put_irq; > + } > ring->sync_to = gen6_ring_sync; > ring->semaphore_register[RCS] = MI_SEMAPHORE_SYNC_VER; > ring->semaphore_register[VCS] = MI_SEMAPHORE_SYNC_VEV; > -- > 1.8.4.2 >
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index c1b178a..83d016c 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1315,7 +1315,10 @@ typedef struct drm_i915_private { struct mutex dpio_lock; /** Cached value of IMR to avoid reads in updating the bitfield */ - u32 irq_mask; + union { + u32 irq_mask; + u32 de_irq_mask[I915_MAX_PIPES]; + }; u32 gt_irq_mask; u32 pm_irq_mask; diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index a9f0cb6..3f0c9e3 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -1118,6 +1118,56 @@ static void snb_gt_irq_handler(struct drm_device *dev, ivybridge_parity_error_irq_handler(dev, gt_iir); } +static irqreturn_t gen8_gt_irq_handler(struct drm_device *dev, + struct drm_i915_private *dev_priv, + u32 master_ctl) +{ + u32 rcs, bcs, vcs; + uint32_t tmp = 0; + irqreturn_t ret = IRQ_NONE; + + if (master_ctl & (GEN8_GT_RCS_IRQ | GEN8_GT_BCS_IRQ)) { + tmp = I915_READ(GEN8_GT_IIR(0)); + if (tmp) { + ret = IRQ_HANDLED; + rcs = tmp >> GEN8_RCS_IRQ_SHIFT; + bcs = tmp >> GEN8_BCS_IRQ_SHIFT; + if (rcs & GT_RENDER_USER_INTERRUPT) + notify_ring(dev, &dev_priv->ring[RCS]); + if (bcs & GT_RENDER_USER_INTERRUPT) + notify_ring(dev, &dev_priv->ring[BCS]); + I915_WRITE(GEN8_GT_IIR(0), tmp); + } else + DRM_ERROR("The master control interrupt lied (GT0)!\n"); + } + + if (master_ctl & GEN8_GT_VCS1_IRQ) { + tmp = I915_READ(GEN8_GT_IIR(1)); + if (tmp) { + ret = IRQ_HANDLED; + vcs = tmp >> GEN8_VCS1_IRQ_SHIFT; + if (vcs & GT_RENDER_USER_INTERRUPT) + notify_ring(dev, &dev_priv->ring[VCS]); + I915_WRITE(GEN8_GT_IIR(1), tmp); + } else + DRM_ERROR("The master control interrupt lied (GT1)!\n"); + } + + if (master_ctl & GEN8_GT_VECS_IRQ) { + tmp = I915_READ(GEN8_GT_IIR(3)); + if (tmp) { + ret = IRQ_HANDLED; + vcs = tmp >> GEN8_VECS_IRQ_SHIFT; + if (vcs & GT_RENDER_USER_INTERRUPT) + notify_ring(dev, &dev_priv->ring[VECS]); + I915_WRITE(GEN8_GT_IIR(3), tmp); + } else + DRM_ERROR("The master control interrupt lied (GT3)!\n"); + } + + return ret; +} + #define HPD_STORM_DETECT_PERIOD 1000 #define HPD_STORM_THRESHOLD 5 @@ -1699,6 +1749,85 @@ static irqreturn_t ironlake_irq_handler(int irq, void *arg) return ret; } +static irqreturn_t gen8_irq_handler(int irq, void *arg) +{ + struct drm_device *dev = arg; + struct drm_i915_private *dev_priv = dev->dev_private; + u32 master_ctl; + irqreturn_t ret = IRQ_NONE; + uint32_t tmp = 0; + + atomic_inc(&dev_priv->irq_received); + + master_ctl = I915_READ(GEN8_MASTER_IRQ); + master_ctl &= ~DE_MASTER_IRQ_CONTROL; + if (!master_ctl) + return IRQ_NONE; + + if ((master_ctl & ~GEN8_RSVD_IRQS) == 0) { + DRM_ERROR("Only received RSVD IRQs 0x%08x\n", master_ctl); + return IRQ_NONE; + } + + I915_WRITE(GEN8_MASTER_IRQ, 0); + + /* NB: Posting read isn't necessary here because we're required to do + * another read no matter what + POSTING_READ(GEN8_MASTER_IRQ); + */ + + ret = gen8_gt_irq_handler(dev, dev_priv, master_ctl); + + if (master_ctl & GEN8_DE_MISC_IRQ) { + tmp = I915_READ(GEN8_DE_MISC_IIR); + if (tmp) { + I915_WRITE(GEN8_DE_MISC_IIR, tmp); + ret = IRQ_HANDLED; + } + + if (tmp & GEN8_DE_MISC_GSE) + intel_opregion_asle_intr(dev); + else if (tmp) + DRM_ERROR("Unexpected DE Misc interrupt\n"); + else + DRM_ERROR("The master control interrupt lied (DE MISC)!\n"); + + } + + if (master_ctl & GEN8_DE_IRQS) { + int de_ret = 0; + int pipe; + for_each_pipe(pipe) { + uint32_t pipe_iir; + + pipe_iir = I915_READ(GEN8_DE_PIPE_IIR(pipe)); + if (pipe_iir & _PIPE_VBLANK) { + drm_handle_vblank(dev, pipe); + } + if (pipe_iir & _PIPE_FLIP_DONE) { + intel_prepare_page_flip(dev, pipe); + intel_finish_page_flip_plane(dev, pipe); + } + + if (pipe_iir & GEN8_DE_PIPE_IRQ_ERRORS) + DRM_ERROR("Errors on pipe %c\n", 'A' + pipe); + + if (pipe_iir) { + de_ret++; + ret = IRQ_HANDLED; + I915_WRITE(GEN8_DE_PIPE_IIR(pipe), pipe_iir); + } + } + if (!de_ret) + DRM_ERROR("The master control interrupt lied (DE PIPE)!\n"); + } + + I915_WRITE(GEN8_MASTER_IRQ, DE_MASTER_IRQ_CONTROL); + POSTING_READ(GEN8_MASTER_IRQ); + + return ret; +} + static void i915_error_wake_up(struct drm_i915_private *dev_priv, bool reset_completed) { @@ -2052,6 +2181,25 @@ static int valleyview_enable_vblank(struct drm_device *dev, int pipe) return 0; } +static int gen8_enable_vblank(struct drm_device *dev, int pipe) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + unsigned long irqflags; + uint32_t imr; + + if (!i915_pipe_enabled(dev, pipe)) + return -EINVAL; + + spin_lock_irqsave(&dev_priv->irq_lock, irqflags); + imr = I915_READ(GEN8_DE_PIPE_IMR(pipe)); + if ((imr & _PIPE_VBLANK) == 1) { + I915_WRITE(GEN8_DE_PIPE_IMR(pipe), imr & ~_PIPE_VBLANK); + POSTING_READ(GEN8_DE_PIPE_IMR(pipe)); + } + spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags); + return 0; +} + /* Called from drm generic code, passed 'crtc' which * we use as a pipe index */ @@ -2100,6 +2248,24 @@ static void valleyview_disable_vblank(struct drm_device *dev, int pipe) spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags); } +static void gen8_disable_vblank(struct drm_device *dev, int pipe) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + unsigned long irqflags; + uint32_t imr; + + if (!i915_pipe_enabled(dev, pipe)) + return; + + spin_lock_irqsave(&dev_priv->irq_lock, irqflags); + imr = I915_READ(GEN8_DE_PIPE_IMR(pipe)); + if ((imr & _PIPE_VBLANK) == 0) { + I915_WRITE(GEN8_DE_PIPE_IMR(pipe), imr | _PIPE_VBLANK); + POSTING_READ(GEN8_DE_PIPE_IMR(pipe)); + } + spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags); +} + static u32 ring_last_seqno(struct intel_ring_buffer *ring) { @@ -2430,6 +2596,51 @@ static void valleyview_irq_preinstall(struct drm_device *dev) POSTING_READ(VLV_IER); } +static void gen8_irq_preinstall(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + int pipe; + + atomic_set(&dev_priv->irq_received, 0); + + I915_WRITE(GEN8_MASTER_IRQ, 0); + POSTING_READ(GEN8_MASTER_IRQ); + + /* IIR can theoretically queue up two events. Be paranoid */ +#define GEN8_IRQ_INIT_NDX(type, which) \ + I915_WRITE(GEN8_##type##_IMR(which), 0xffffffff); \ + POSTING_READ(GEN8_##type##_IMR(which)); \ + I915_WRITE(GEN8_##type##_IER(which), 0); \ + I915_WRITE(GEN8_##type##_IIR(which), 0xffffffff); \ + POSTING_READ(GEN8_##type##_IIR(which)); \ + I915_WRITE(GEN8_##type##_IIR(which), 0xffffffff) + +#define GEN8_IRQ_INIT(type) \ + I915_WRITE(GEN8_##type##_IMR, 0xffffffff); \ + POSTING_READ(GEN8_##type##_IMR); \ + I915_WRITE(GEN8_##type##_IER, 0); \ + I915_WRITE(GEN8_##type##_IIR, 0xffffffff); \ + POSTING_READ(GEN8_##type##_IIR); \ + I915_WRITE(GEN8_##type##_IIR, 0xffffffff) + + GEN8_IRQ_INIT_NDX(GT, 0); + GEN8_IRQ_INIT_NDX(GT, 1); + GEN8_IRQ_INIT_NDX(GT, 2); + GEN8_IRQ_INIT_NDX(GT, 3); + + for_each_pipe(pipe) { + GEN8_IRQ_INIT_NDX(DE_PIPE, pipe); + } + + GEN8_IRQ_INIT(DE_PORT); + GEN8_IRQ_INIT(DE_MISC); + GEN8_IRQ_INIT(PCU); +#undef GEN8_IRQ_INIT +#undef GEN8_IRQ_INIT_NDX + + POSTING_READ(GEN8_PCU_IIR); +} + static void ibx_hpd_irq_setup(struct drm_device *dev) { drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; @@ -2635,6 +2846,114 @@ static int valleyview_irq_postinstall(struct drm_device *dev) return 0; } +static void gen8_gt_irq_postinstall(struct drm_i915_private *dev_priv) +{ + int i; + + /* These are interrupts we'll toggle with the ring mask register */ + uint32_t gt_interrupts[] = { + GT_RENDER_USER_INTERRUPT << GEN8_RCS_IRQ_SHIFT | + GT_RENDER_L3_PARITY_ERROR_INTERRUPT | + GT_RENDER_USER_INTERRUPT << GEN8_BCS_IRQ_SHIFT, + GT_RENDER_USER_INTERRUPT << GEN8_VCS1_IRQ_SHIFT | + GT_RENDER_USER_INTERRUPT << GEN8_VCS2_IRQ_SHIFT, + 0, + GT_RENDER_USER_INTERRUPT << GEN8_VECS_IRQ_SHIFT + }; + + for (i = 0; i < ARRAY_SIZE(gt_interrupts); i++) { + u32 tmp = I915_READ(GEN8_GT_IIR(i)); + if (tmp) + DRM_ERROR("Interrupt (%d) should have been masked in pre-install 0x%08x\n", + i, tmp); + I915_WRITE(GEN8_GT_IMR(i), ~gt_interrupts[i]); + I915_WRITE(GEN8_GT_IER(i), gt_interrupts[i]); + } + POSTING_READ(GEN8_GT_IER(0)); +} + +static void gen8_de_irq_postinstall(struct drm_i915_private *dev_priv) +{ + struct drm_device *dev = dev_priv->dev; + uint32_t de_pipe_enables = _PIPE_FLIP_DONE | + _PIPE_SCAN_LINE_EVENT | + _PIPE_VBLANK | + GEN8_DE_PIPE_IRQ_ERRORS; + int pipe; + dev_priv->de_irq_mask[PIPE_A] = ~de_pipe_enables; + dev_priv->de_irq_mask[PIPE_B] = ~de_pipe_enables; + dev_priv->de_irq_mask[PIPE_C] = ~de_pipe_enables; + + for_each_pipe(pipe) { + u32 tmp = I915_READ(GEN8_DE_PIPE_IIR(pipe)); + if (tmp) + DRM_ERROR("Interrupt (%d) should have been masked in pre-install 0x%08x\n", + pipe, tmp); + I915_WRITE(GEN8_DE_PIPE_IMR(pipe), dev_priv->de_irq_mask[pipe]); + I915_WRITE(GEN8_DE_PIPE_IER(pipe), de_pipe_enables); + } + POSTING_READ(GEN8_DE_PIPE_ISR(0)); + + I915_WRITE(GEN8_DE_PORT_IMR, ~_PORT_DP_A_HOTPLUG); + I915_WRITE(GEN8_DE_PORT_IER, _PORT_DP_A_HOTPLUG); + POSTING_READ(GEN8_DE_PORT_IER); +} + +static int gen8_irq_postinstall(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + + gen8_gt_irq_postinstall(dev_priv); + gen8_de_irq_postinstall(dev_priv); + + ibx_irq_postinstall(dev); + + I915_WRITE(GEN8_MASTER_IRQ, DE_MASTER_IRQ_CONTROL); + POSTING_READ(GEN8_MASTER_IRQ); + + return 0; +} + +static void gen8_irq_uninstall(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + int pipe; + + if (!dev_priv) + return; + + atomic_set(&dev_priv->irq_received, 0); + + I915_WRITE(GEN8_MASTER_IRQ, 0); + +#define GEN8_IRQ_FINI_NDX(type, which) \ + I915_WRITE(GEN8_##type##_IMR(which), 0xffffffff); \ + I915_WRITE(GEN8_##type##_IER(which), 0); \ + I915_WRITE(GEN8_##type##_IIR(which), 0xffffffff) + +#define GEN8_IRQ_FINI(type) \ + I915_WRITE(GEN8_##type##_IMR, 0xffffffff); \ + I915_WRITE(GEN8_##type##_IER, 0); \ + I915_WRITE(GEN8_##type##_IIR, 0xffffffff) + + GEN8_IRQ_FINI_NDX(GT, 0); + GEN8_IRQ_FINI_NDX(GT, 1); + GEN8_IRQ_FINI_NDX(GT, 2); + GEN8_IRQ_FINI_NDX(GT, 3); + + for_each_pipe(pipe) { + GEN8_IRQ_FINI_NDX(DE_PIPE, pipe); + } + + GEN8_IRQ_FINI(DE_PORT); + GEN8_IRQ_FINI(DE_MISC); + GEN8_IRQ_FINI(PCU); +#undef GEN8_IRQ_FINI +#undef GEN8_IRQ_FINI_NDX + + POSTING_READ(GEN8_PCU_IIR); +} + static void valleyview_irq_uninstall(struct drm_device *dev) { drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; @@ -3414,6 +3733,14 @@ void intel_irq_init(struct drm_device *dev) dev->driver->enable_vblank = valleyview_enable_vblank; dev->driver->disable_vblank = valleyview_disable_vblank; dev_priv->display.hpd_irq_setup = i915_hpd_irq_setup; + } else if (IS_GEN8(dev)) { + dev->driver->irq_handler = gen8_irq_handler; + dev->driver->irq_preinstall = gen8_irq_preinstall; + dev->driver->irq_postinstall = gen8_irq_postinstall; + dev->driver->irq_uninstall = gen8_irq_uninstall; + dev->driver->enable_vblank = gen8_enable_vblank; + dev->driver->disable_vblank = gen8_disable_vblank; + dev_priv->display.hpd_irq_setup = ibx_hpd_irq_setup; } else if (HAS_PCH_SPLIT(dev)) { dev->driver->irq_handler = ironlake_irq_handler; dev->driver->irq_preinstall = ironlake_irq_preinstall; diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index fb6ad89..b801b88 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -3989,6 +3989,69 @@ #define GTIIR 0x44018 #define GTIER 0x4401c +#define GEN8_MASTER_IRQ 0x44200 +#define GEN8_PCU_IRQ (1<<30) +#define GEN8_DE_PCH_IRQ (1<<23) +#define GEN8_DE_MISC_IRQ (1<<22) +#define GEN8_DE_PORT_IRQ (1<<20) +#define GEN8_DE_PIPE_C_IRQ (1<<18) +#define GEN8_DE_PIPE_B_IRQ (1<<17) +#define GEN8_DE_PIPE_A_IRQ (1<<16) +#define GEN8_GT_VECS_IRQ (1<<6) +#define GEN8_GT_VCS2_IRQ (1<<3) +#define GEN8_GT_VCS1_IRQ (1<<2) +#define GEN8_GT_BCS_IRQ (1<<1) +#define GEN8_GT_RCS_IRQ (1<<0) +/* Lazy definition */ +#define GEN8_GT_IRQS 0x000000ff +#define GEN8_DE_IRQS 0x01ff0000 +#define GEN8_RSVD_IRQS 0xB700ff00 + +#define GEN8_GT_ISR(which) (0x44300 + (0x10 * (which))) +#define GEN8_GT_IMR(which) (0x44304 + (0x10 * (which))) +#define GEN8_GT_IIR(which) (0x44308 + (0x10 * (which))) +#define GEN8_GT_IER(which) (0x4430c + (0x10 * (which))) + +#define GEN8_BCS_IRQ_SHIFT 16 +#define GEN8_RCS_IRQ_SHIFT 0 +#define GEN8_VCS2_IRQ_SHIFT 16 +#define GEN8_VCS1_IRQ_SHIFT 0 +#define GEN8_VECS_IRQ_SHIFT 0 + +#define GEN8_DE_PIPE_ISR(pipe) (0x44400 + (0x10 * (pipe))) +#define GEN8_DE_PIPE_IMR(pipe) (0x44404 + (0x10 * (pipe))) +#define GEN8_DE_PIPE_IIR(pipe) (0x44408 + (0x10 * (pipe))) +#define GEN8_DE_PIPE_IER(pipe) (0x4440c + (0x10 * (pipe))) +#define _PIPE_UNDERRUN (1 << 31) +#define _PIPE_CDCLK_CRC_ERROR (1 << 29) +#define _PIPE_CURSOR_FAULT (1 << 10) +#define _PIPE_SPRITE_FAULT (1 << 9) +#define _PIPE_PRIMARY_FAULT (1 << 8) +#define _PIPE_SPRITE_FLIP_DONE (1 << 5) +#define _PIPE_FLIP_DONE (1 << 4) +#define _PIPE_SCAN_LINE_EVENT (1 << 3) +#define _PIPE_VBLANK (1 << 0) +#define GEN8_DE_PIPE_IRQ_ERRORS (_PIPE_UNDERRUN | _PIPE_CDCLK_CRC_ERROR | \ + _PIPE_CURSOR_FAULT | _PIPE_SPRITE_FAULT | \ + _PIPE_PRIMARY_FAULT) + +#define GEN8_DE_PORT_ISR 0x44440 +#define GEN8_DE_PORT_IMR 0x44444 +#define GEN8_DE_PORT_IIR 0x44448 +#define GEN8_DE_PORT_IER 0x4444c +#define _PORT_DP_A_HOTPLUG (1 << 3) + +#define GEN8_DE_MISC_ISR 0x44460 +#define GEN8_DE_MISC_IMR 0x44464 +#define GEN8_DE_MISC_IIR 0x44468 +#define GEN8_DE_MISC_IER 0x4446c +#define GEN8_DE_MISC_GSE (1 << 27) + +#define GEN8_PCU_ISR 0x444e0 +#define GEN8_PCU_IMR 0x444e4 +#define GEN8_PCU_IIR 0x444e8 +#define GEN8_PCU_IER 0x444ec + #define ILK_DISPLAY_CHICKEN2 0x42004 /* Required on all Ironlake and Sandybridge according to the B-Spec. */ #define ILK_ELPIN_409_SELECT (1 << 25) diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index 2dec134..b2161f2 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -1066,6 +1066,48 @@ hsw_vebox_put_irq(struct intel_ring_buffer *ring) spin_unlock_irqrestore(&dev_priv->irq_lock, flags); } +static bool +gen8_ring_get_irq(struct intel_ring_buffer *ring) +{ + struct drm_device *dev = ring->dev; + struct drm_i915_private *dev_priv = dev->dev_private; + unsigned long flags; + + if (!dev->irq_enabled) + return false; + + spin_lock_irqsave(&dev_priv->irq_lock, flags); + if (ring->irq_refcount++ == 0) { + if (HAS_L3_DPF(dev) && ring->id == RCS) + I915_WRITE_IMR(ring, ~(ring->irq_enable_mask | + GT_RENDER_L3_PARITY_ERROR_INTERRUPT)); + else + I915_WRITE_IMR(ring, ~ring->irq_enable_mask); + POSTING_READ(RING_IMR(ring->mmio_base)); + } + spin_unlock_irqrestore(&dev_priv->irq_lock, flags); + + return true; +} + +static void +gen8_ring_put_irq(struct intel_ring_buffer *ring) +{ + struct drm_device *dev = ring->dev; + drm_i915_private_t *dev_priv = dev->dev_private; + unsigned long flags; + + spin_lock_irqsave(&dev_priv->irq_lock, flags); + if (--ring->irq_refcount == 0) { + if (HAS_L3_DPF(dev) && ring->id == RCS) + I915_WRITE_IMR(ring, ~GT_RENDER_L3_PARITY_ERROR_INTERRUPT); + else + I915_WRITE_IMR(ring, ~0); + POSTING_READ(RING_IMR(ring->mmio_base)); + } + spin_unlock_irqrestore(&dev_priv->irq_lock, flags); +} + static int i965_dispatch_execbuffer(struct intel_ring_buffer *ring, u32 offset, u32 length, @@ -1732,8 +1774,13 @@ int intel_init_render_ring_buffer(struct drm_device *dev) ring->flush = gen7_render_ring_flush; if (INTEL_INFO(dev)->gen == 6) ring->flush = gen6_render_ring_flush; - ring->irq_get = gen6_ring_get_irq; - ring->irq_put = gen6_ring_put_irq; + if (INTEL_INFO(dev)->gen >= 8) { + ring->irq_get = gen8_ring_get_irq; + ring->irq_put = gen8_ring_put_irq; + } else { + ring->irq_get = gen6_ring_get_irq; + ring->irq_put = gen6_ring_put_irq; + } ring->irq_enable_mask = GT_RENDER_USER_INTERRUPT; ring->get_seqno = gen6_ring_get_seqno; ring->set_seqno = ring_set_seqno; @@ -1897,9 +1944,15 @@ int intel_init_bsd_ring_buffer(struct drm_device *dev) ring->add_request = gen6_add_request; ring->get_seqno = gen6_ring_get_seqno; ring->set_seqno = ring_set_seqno; - ring->irq_enable_mask = GT_BSD_USER_INTERRUPT; - ring->irq_get = gen6_ring_get_irq; - ring->irq_put = gen6_ring_put_irq; + if (INTEL_INFO(dev)->gen >= 8) { + ring->irq_enable_mask = GT_RENDER_USER_INTERRUPT << GEN8_VCS1_IRQ_SHIFT; + ring->irq_get = gen8_ring_get_irq; + ring->irq_put = gen8_ring_put_irq; + } else { + ring->irq_enable_mask = GT_BSD_USER_INTERRUPT; + ring->irq_get = gen6_ring_get_irq; + ring->irq_put = gen6_ring_put_irq; + } ring->dispatch_execbuffer = gen6_ring_dispatch_execbuffer; ring->sync_to = gen6_ring_sync; ring->semaphore_register[RCS] = MI_SEMAPHORE_SYNC_VR; @@ -1946,9 +1999,15 @@ int intel_init_blt_ring_buffer(struct drm_device *dev) ring->add_request = gen6_add_request; ring->get_seqno = gen6_ring_get_seqno; ring->set_seqno = ring_set_seqno; - ring->irq_enable_mask = GT_BLT_USER_INTERRUPT; - ring->irq_get = gen6_ring_get_irq; - ring->irq_put = gen6_ring_put_irq; + if (INTEL_INFO(dev)->gen >= 8) { + ring->irq_enable_mask = GT_RENDER_USER_INTERRUPT << GEN8_BCS_IRQ_SHIFT; + ring->irq_get = gen8_ring_get_irq; + ring->irq_put = gen8_ring_put_irq; + } else { + ring->irq_enable_mask = GT_BLT_USER_INTERRUPT; + ring->irq_get = gen6_ring_get_irq; + ring->irq_put = gen6_ring_put_irq; + } ring->dispatch_execbuffer = gen6_ring_dispatch_execbuffer; ring->sync_to = gen6_ring_sync; ring->semaphore_register[RCS] = MI_SEMAPHORE_SYNC_BR; @@ -1978,10 +2037,19 @@ int intel_init_vebox_ring_buffer(struct drm_device *dev) ring->add_request = gen6_add_request; ring->get_seqno = gen6_ring_get_seqno; ring->set_seqno = ring_set_seqno; - ring->irq_enable_mask = PM_VEBOX_USER_INTERRUPT; - ring->irq_get = hsw_vebox_get_irq; - ring->irq_put = hsw_vebox_put_irq; ring->dispatch_execbuffer = gen6_ring_dispatch_execbuffer; + + if (INTEL_INFO(dev)->gen >= 8) { + ring->irq_enable_mask = + (GT_RENDER_USER_INTERRUPT << GEN8_VECS_IRQ_SHIFT) | + GT_RENDER_CS_MASTER_ERROR_INTERRUPT; + ring->irq_get = gen8_ring_get_irq; + ring->irq_put = gen8_ring_put_irq; + } else { + ring->irq_enable_mask = PM_VEBOX_USER_INTERRUPT; + ring->irq_get = hsw_vebox_get_irq; + ring->irq_put = hsw_vebox_put_irq; + } ring->sync_to = gen6_ring_sync; ring->semaphore_register[RCS] = MI_SEMAPHORE_SYNC_VER; ring->semaphore_register[VCS] = MI_SEMAPHORE_SYNC_VEV;