static int i915_wait_irq(drm_device_t * dev, int irq_nr) { drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; int ret = 0; DRM_DEBUG("%s irq_nr=%d breadcrumb=%d\n", __FUNCTION__, irq_nr, READ_BREADCRUMB(dev_priv)); if (READ_BREADCRUMB(dev_priv) >= irq_nr) return 0; dev_priv->sarea_priv->perf_boxes |= I915_BOX_WAIT; DRM_WAIT_ON(ret, dev_priv->irq_queue, 3 * DRM_HZ, READ_BREADCRUMB(dev_priv) >= irq_nr); if (ret == DRM_ERR(EBUSY)) { DRM_ERROR("%s: EBUSY -- rec: %d emitted: %d\n", __FUNCTION__, READ_BREADCRUMB(dev_priv), (int)dev_priv->counter); } dev_priv->sarea_priv->last_dispatch = READ_BREADCRUMB(dev_priv); return ret; }
irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS) { drm_device_t *dev = (drm_device_t *) arg; drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; u16 temp; temp = I915_READ16(I915REG_INT_IDENTITY_R); temp &= (USER_INT_FLAG | VSYNC_PIPEA_FLAG | VSYNC_PIPEB_FLAG); DRM_DEBUG("%s flag=%08x\n", __FUNCTION__, temp); if (temp == 0) return IRQ_NONE; I915_WRITE16(I915REG_INT_IDENTITY_R, temp); dev_priv->sarea_priv->last_dispatch = READ_BREADCRUMB(dev_priv); if (temp & USER_INT_FLAG) DRM_WAKEUP(&dev_priv->irq_queue); if (temp & (VSYNC_PIPEA_FLAG | VSYNC_PIPEB_FLAG)) { atomic_inc(&dev->vbl_received); DRM_WAKEUP(&dev->vbl_queue); drm_vbl_send_signals(dev); } return IRQ_HANDLED; }
static void i915_initiate_rwflush(struct drm_i915_private *dev_priv, struct drm_fence_class_manager *fc) { if ((fc->pending_flush & DRM_I915_FENCE_TYPE_RW) && !dev_priv->flush_pending) { dev_priv->flush_sequence = (uint32_t) READ_BREADCRUMB(dev_priv); dev_priv->flush_flags = fc->pending_flush; dev_priv->saved_flush_status = READ_HWSP(dev_priv, 0); I915_WRITE(I915REG_INSTPM, (1 << 5) | (1 << 21)); dev_priv->flush_pending = 1; fc->pending_flush &= ~DRM_I915_FENCE_TYPE_RW; } }
static void i915_fence_poll(struct drm_device *dev, uint32_t fence_class, uint32_t waiting_types) { struct drm_i915_private *dev_priv = (struct drm_i915_private *) dev->dev_private; struct drm_fence_manager *fm = &dev->fm; struct drm_fence_class_manager *fc = &fm->fence_class[0]; uint32_t flush_flags = 0; uint32_t flush_sequence = 0; uint32_t i_status; uint32_t sequence; if (unlikely(!dev_priv)) return; /* * First, report any executed sync flush: */ if (dev_priv->flush_pending) { i_status = READ_HWSP(dev_priv, 0); if ((i_status & (1 << 12)) != (dev_priv->saved_flush_status & (1 << 12))) { flush_flags = dev_priv->flush_flags; flush_sequence = dev_priv->flush_sequence; dev_priv->flush_pending = 0; drm_fence_handler(dev, 0, flush_sequence, flush_flags, 0); } } /* * Report A new breadcrumb, and adjust IRQs. */ if (waiting_types & DRM_FENCE_TYPE_EXE) { sequence = READ_BREADCRUMB(dev_priv); if (sequence != dev_priv->reported_sequence || !dev_priv->reported_sequence_valid) { drm_fence_handler(dev, 0, sequence, DRM_FENCE_TYPE_EXE, 0); dev_priv->reported_sequence = sequence; dev_priv->reported_sequence_valid = 1; } if (dev_priv->fence_irq_on && !(waiting_types & DRM_FENCE_TYPE_EXE)) { i915_user_irq_off(dev_priv); dev_priv->fence_irq_on = 0; } else if (!dev_priv->fence_irq_on && (waiting_types & DRM_FENCE_TYPE_EXE)) { i915_user_irq_on(dev_priv); dev_priv->fence_irq_on = 1; } } /* * There may be new RW flushes pending. Start them. */ i915_initiate_rwflush(dev_priv, fc); /* * And possibly, but unlikely, they finish immediately. */ if (dev_priv->flush_pending) { i_status = READ_HWSP(dev_priv, 0); if (unlikely((i_status & (1 << 12)) != (dev_priv->saved_flush_status & (1 << 12)))) { flush_flags = dev_priv->flush_flags; flush_sequence = dev_priv->flush_sequence; dev_priv->flush_pending = 0; drm_fence_handler(dev, 0, flush_sequence, flush_flags, 0); } } }