p->devnum != PCI_SLOT(dev->pdev->devfn) || p->funcnum != PCI_FUNC(dev->pdev->devfn))
return -EINVAL;
- p->irq = dev->irq;
+ p->irq = dev->pdev->irq;
DRM_DEBUG("%d:%d:%d => IRQ %d\n", p->busnum, p->devnum, p->funcnum,
p->irq);
if (!drm_core_check_feature(dev, DRIVER_HAVE_IRQ))
return -EINVAL;
- if (dev->irq == 0)
+ if (dev->pdev->irq == 0)
return -EINVAL;
mutex_lock(&dev->struct_mutex);
dev->irq_enabled = 1;
mutex_unlock(&dev->struct_mutex);
- DRM_DEBUG("irq=%d\n", dev->irq);
+ DRM_DEBUG("irq=%d\n", dev->pdev->irq);
if (drm_core_check_feature(dev, DRIVER_IRQ_VBL)) {
init_waitqueue_head(&dev->vbl_queue);
if (drm_core_check_feature(dev, DRIVER_IRQ_SHARED))
sh_flags = IRQF_SHARED;
- ret = request_irq(dev->irq, dev->driver->irq_handler,
+ ret = request_irq(dev->pdev->irq, dev->driver->irq_handler,
sh_flags, dev->devname, dev);
+ /* Expose the device irq number to drivers that want to export it for
+ * whatever reason.
+ */
+ dev->irq = dev->pdev->irq;
if (ret < 0) {
mutex_lock(&dev->struct_mutex);
dev->irq_enabled = 0;
if (!irq_enabled)
return -EINVAL;
- DRM_DEBUG("irq=%d\n", dev->irq);
+ DRM_DEBUG("irq=%d\n", dev->pdev->irq);
dev->driver->irq_uninstall(dev);
- free_irq(dev->irq, dev);
+ free_irq(dev->pdev->irq, dev);
dev->locked_tasklet_func = NULL;
if (!drm_core_check_feature(dev, DRIVER_HAVE_IRQ))
return 0;
if (dev->if_version < DRM_IF_VERSION(1, 2) &&
- ctl->irq != dev->irq)
+ ctl->irq != dev->pdev->irq)
return -EINVAL;
return drm_irq_install(dev);
case DRM_UNINST_HANDLER:
int ret = 0;
unsigned int flags, seq;
- if ((!dev->irq) || (!dev->irq_enabled))
+ if ((!dev->pdev->irq) || (!dev->irq_enabled))
return -EINVAL;
if (vblwait->request.type &
#define MAX_NOPID ((u32)~0)
+/** These are the interrupts used by the driver */
+#define I915_INTERRUPT_ENABLE_MASK (I915_USER_INTERRUPT | \
+ I915_DISPLAY_PIPE_A_VBLANK_INTERRUPT | \
+ I915_DISPLAY_PIPE_B_VBLANK_INTERRUPT)
+
+static inline void
+i915_enable_irq(drm_i915_private_t *dev_priv, u32 mask)
+{
+ if ((dev_priv->irq_mask_reg & mask) != 0) {
+ dev_priv->irq_mask_reg &= ~mask;
+ I915_WRITE(IMR, dev_priv->irq_mask_reg);
+ (void) I915_READ(IMR);
+ }
+}
+
+static inline void
+i915_disable_irq(drm_i915_private_t *dev_priv, u32 mask)
+{
+ if ((dev_priv->irq_mask_reg & mask) != mask) {
+ dev_priv->irq_mask_reg |= mask;
+ I915_WRITE(IMR, dev_priv->irq_mask_reg);
+ (void) I915_READ(IMR);
+ }
+}
+
/**
* Emit blits for scheduled buffer swaps.
*
{
struct drm_device *dev = (struct drm_device *) arg;
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
- u16 temp;
u32 pipea_stats, pipeb_stats;
+ u32 iir;
pipea_stats = I915_READ(PIPEASTAT);
pipeb_stats = I915_READ(PIPEBSTAT);
- temp = I915_READ16(IIR);
-
- temp &= (I915_USER_INTERRUPT |
- I915_DISPLAY_PIPE_A_VBLANK_INTERRUPT |
- I915_DISPLAY_PIPE_B_VBLANK_INTERRUPT);
+ if (dev->pdev->msi_enabled)
+ I915_WRITE(IMR, ~0);
+ iir = I915_READ(IIR);
- DRM_DEBUG("%s flag=%08x\n", __FUNCTION__, temp);
+ DRM_DEBUG("iir=%08x\n", iir);
- if (temp == 0)
+ if (iir == 0) {
+ if (dev->pdev->msi_enabled) {
+ I915_WRITE(IMR, dev_priv->irq_mask_reg);
+ (void) I915_READ(IMR);
+ }
return IRQ_NONE;
+ }
- I915_WRITE16(IIR, temp);
- (void) I915_READ16(IIR);
- DRM_READMEMORYBARRIER();
+ I915_WRITE(IIR, iir);
+ if (dev->pdev->msi_enabled)
+ I915_WRITE(IMR, dev_priv->irq_mask_reg);
+ (void) I915_READ(IIR); /* Flush posted writes */
dev_priv->sarea_priv->last_dispatch = READ_BREADCRUMB(dev_priv);
- if (temp & I915_USER_INTERRUPT)
+ if (iir & I915_USER_INTERRUPT)
DRM_WAKEUP(&dev_priv->irq_queue);
- if (temp & (I915_DISPLAY_PIPE_A_VBLANK_INTERRUPT |
- I915_DISPLAY_PIPE_B_VBLANK_INTERRUPT)) {
+ if (iir & (I915_DISPLAY_PIPE_A_VBLANK_INTERRUPT |
+ I915_DISPLAY_PIPE_B_VBLANK_INTERRUPT)) {
int vblank_pipe = dev_priv->vblank_pipe;
if ((vblank_pipe &
(DRM_I915_VBLANK_PIPE_A | DRM_I915_VBLANK_PIPE_B))
== (DRM_I915_VBLANK_PIPE_A | DRM_I915_VBLANK_PIPE_B)) {
- if (temp & I915_DISPLAY_PIPE_A_VBLANK_INTERRUPT)
+ if (iir & I915_DISPLAY_PIPE_A_VBLANK_INTERRUPT)
atomic_inc(&dev->vbl_received);
- if (temp & I915_DISPLAY_PIPE_B_VBLANK_INTERRUPT)
+ if (iir & I915_DISPLAY_PIPE_B_VBLANK_INTERRUPT)
atomic_inc(&dev->vbl_received2);
- } else if (((temp & I915_DISPLAY_PIPE_A_VBLANK_INTERRUPT) &&
+ } else if (((iir & I915_DISPLAY_PIPE_A_VBLANK_INTERRUPT) &&
(vblank_pipe & DRM_I915_VBLANK_PIPE_A)) ||
- ((temp & I915_DISPLAY_PIPE_B_VBLANK_INTERRUPT) &&
+ ((iir & I915_DISPLAY_PIPE_B_VBLANK_INTERRUPT) &&
(vblank_pipe & DRM_I915_VBLANK_PIPE_B)))
atomic_inc(&dev->vbl_received);
return dev_priv->counter;
}
+static void i915_user_irq_get(struct drm_device *dev)
+{
+ drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
+
+ spin_lock(&dev_priv->user_irq_lock);
+ if (dev->irq_enabled && (++dev_priv->user_irq_refcount == 1))
+ i915_enable_irq(dev_priv, I915_USER_INTERRUPT);
+ spin_unlock(&dev_priv->user_irq_lock);
+}
+
+static void i915_user_irq_put(struct drm_device *dev)
+{
+ drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
+
+ spin_lock(&dev_priv->user_irq_lock);
+ BUG_ON(dev->irq_enabled && dev_priv->user_irq_refcount <= 0);
+ if (dev->irq_enabled && (--dev_priv->user_irq_refcount == 0))
+ i915_disable_irq(dev_priv, I915_USER_INTERRUPT);
+ spin_unlock(&dev_priv->user_irq_lock);
+}
+
static int i915_wait_irq(struct drm_device * dev, int irq_nr)
{
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
DRM_DEBUG("irq_nr=%d breadcrumb=%d\n", irq_nr,
READ_BREADCRUMB(dev_priv));
- if (READ_BREADCRUMB(dev_priv) >= irq_nr)
+ if (READ_BREADCRUMB(dev_priv) >= irq_nr) {
+ dev_priv->sarea_priv->last_dispatch = READ_BREADCRUMB(dev_priv);
return 0;
+ }
dev_priv->sarea_priv->perf_boxes |= I915_BOX_WAIT;
+ i915_user_irq_get(dev);
DRM_WAIT_ON(ret, dev_priv->irq_queue, 3 * DRM_HZ,
READ_BREADCRUMB(dev_priv) >= irq_nr);
+ i915_user_irq_put(dev);
if (ret == -EBUSY) {
DRM_ERROR("EBUSY -- rec: %d emitted: %d\n",
return i915_wait_irq(dev, irqwait->irq_seq);
}
-static void i915_enable_interrupt (struct drm_device *dev)
-{
- drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
- u16 flag;
-
- flag = 0;
- if (dev_priv->vblank_pipe & DRM_I915_VBLANK_PIPE_A)
- flag |= I915_DISPLAY_PIPE_A_VBLANK_INTERRUPT;
- if (dev_priv->vblank_pipe & DRM_I915_VBLANK_PIPE_B)
- flag |= I915_DISPLAY_PIPE_B_VBLANK_INTERRUPT;
-
- I915_WRITE16(IER, I915_USER_INTERRUPT | flag);
-}
-
/* Set the vblank monitor pipe
*/
int i915_vblank_pipe_set(struct drm_device *dev, void *data,
{
drm_i915_private_t *dev_priv = dev->dev_private;
drm_i915_vblank_pipe_t *pipe = data;
+ u32 enable_mask = 0, disable_mask = 0;
if (!dev_priv) {
DRM_ERROR("called with no initialization\n");
return -EINVAL;
}
- dev_priv->vblank_pipe = pipe->pipe;
+ if (pipe->pipe & DRM_I915_VBLANK_PIPE_A)
+ enable_mask |= I915_DISPLAY_PIPE_A_VBLANK_INTERRUPT;
+ else
+ disable_mask |= I915_DISPLAY_PIPE_A_VBLANK_INTERRUPT;
+
+ if (pipe->pipe & DRM_I915_VBLANK_PIPE_B)
+ enable_mask |= I915_DISPLAY_PIPE_B_VBLANK_INTERRUPT;
+ else
+ disable_mask |= I915_DISPLAY_PIPE_B_VBLANK_INTERRUPT;
- i915_enable_interrupt (dev);
+ i915_enable_irq(dev_priv, enable_mask);
+ i915_disable_irq(dev_priv, disable_mask);
+
+ dev_priv->vblank_pipe = pipe->pipe;
return 0;
}
return -EINVAL;
}
- flag = I915_READ(IER);
+ flag = I915_READ(IMR);
pipe->pipe = 0;
if (flag & I915_DISPLAY_PIPE_A_VBLANK_INTERRUPT)
pipe->pipe |= DRM_I915_VBLANK_PIPE_A;
{
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
- I915_WRITE16(HWSTAM, 0xfffe);
- I915_WRITE16(IMR, 0x0);
- I915_WRITE16(IER, 0x0);
+ I915_WRITE(HWSTAM, 0xfffe);
+ I915_WRITE(IMR, 0x0);
+ I915_WRITE(IER, 0x0);
}
void i915_driver_irq_postinstall(struct drm_device * dev)
if (!dev_priv->vblank_pipe)
dev_priv->vblank_pipe = DRM_I915_VBLANK_PIPE_A;
- i915_enable_interrupt(dev);
+
+ /* Set initial unmasked IRQs to just the selected vblank pipes. */
+ dev_priv->irq_mask_reg = ~0;
+ if (dev_priv->vblank_pipe & DRM_I915_VBLANK_PIPE_A)
+ dev_priv->irq_mask_reg &= ~I915_DISPLAY_PIPE_A_VBLANK_INTERRUPT;
+ if (dev_priv->vblank_pipe & DRM_I915_VBLANK_PIPE_B)
+ dev_priv->irq_mask_reg &= ~I915_DISPLAY_PIPE_B_VBLANK_INTERRUPT;
+
+ I915_WRITE(IMR, dev_priv->irq_mask_reg);
+ I915_WRITE(IER, I915_INTERRUPT_ENABLE_MASK);
+ (void) I915_READ(IER);
+
DRM_INIT_WAITQUEUE(&dev_priv->irq_queue);
}
if (!dev_priv)
return;
- I915_WRITE16(HWSTAM, 0xffff);
- I915_WRITE16(IMR, 0xffff);
- I915_WRITE16(IER, 0x0);
+ I915_WRITE(HWSTAM, 0xffff);
+ I915_WRITE(IMR, 0xffff);
+ I915_WRITE(IER, 0x0);
- temp = I915_READ16(IIR);
- I915_WRITE16(IIR, temp);
+ temp = I915_READ(IIR);
+ I915_WRITE(IIR, temp);
}