diff options
Diffstat (limited to 'shared-core/i915_dma.c')
-rw-r--r-- | shared-core/i915_dma.c | 71 |
1 files changed, 64 insertions, 7 deletions
diff --git a/shared-core/i915_dma.c b/shared-core/i915_dma.c index 60b405d4..a948834a 100644 --- a/shared-core/i915_dma.c +++ b/shared-core/i915_dma.c @@ -41,10 +41,14 @@ int i915_wait_ring(struct drm_device * dev, int n, const char *caller) drm_i915_private_t *dev_priv = dev->dev_private; drm_i915_ring_buffer_t *ring = &(dev_priv->ring); u32 last_head = I915_READ(LP_RING + RING_HEAD) & HEAD_ADDR; + u32 acthd_reg = IS_I965G(dev) ? I965REG_ACTHD : I915REG_ACTHD; + u32 last_acthd = I915_READ(acthd_reg); + u32 acthd; int i; - for (i = 0; i < 10000; i++) { + for (i = 0; i < 100000; i++) { ring->head = I915_READ(LP_RING + RING_HEAD) & HEAD_ADDR; + acthd = I915_READ(acthd_reg); ring->space = ring->head - (ring->tail + 8); if (ring->space < 0) ring->space += ring->Size; @@ -54,13 +58,41 @@ int i915_wait_ring(struct drm_device * dev, int n, const char *caller) if (ring->head != last_head) i = 0; + if (acthd != last_acthd) + i = 0; + last_head = ring->head; - DRM_UDELAY(1); + last_acthd = acthd; + msleep_interruptible (10); } return -EBUSY; } +#if I915_RING_VALIDATE +/** + * Validate the cached ring tail value + * + * If the X server writes to the ring and DRM doesn't + * reload the head and tail pointers, it will end up writing + * data to the wrong place in the ring, causing havoc. + */ +void i915_ring_validate(struct drm_device *dev, const char *func, int line) +{ + drm_i915_private_t *dev_priv = dev->dev_private; + drm_i915_ring_buffer_t *ring = &(dev_priv->ring); + u32 tail = I915_READ(LP_RING+RING_TAIL) & HEAD_ADDR; + u32 head = I915_READ(LP_RING+RING_HEAD) & HEAD_ADDR; + + if (tail != ring->tail) { + DRM_ERROR("%s:%d head sw %x, hw %x. tail sw %x hw %x\n", + func, line, + ring->head, head, ring->tail, tail); + BUG_ON(1); + } +} +#endif + void i915_kernel_lost_context(struct drm_device * dev) { drm_i915_private_t *dev_priv = dev->dev_private; @@ -459,9 +491,9 @@ static int i915_emit_cmds(struct drm_device *dev, int __user *buffer, return 0; } -static int i915_emit_box(struct drm_device * dev, - struct drm_clip_rect __user * boxes, - int i, int DR1, int DR4) +int i915_emit_box(struct drm_device * dev, + struct drm_clip_rect __user * boxes, + int i, int DR1, int DR4) { drm_i915_private_t *dev_priv = dev->dev_private; struct drm_clip_rect box; @@ -517,7 +549,7 @@ void i915_emit_breadcrumb(struct drm_device *dev) BEGIN_LP_RING(4); OUT_RING(CMD_STORE_DWORD_IDX); - OUT_RING(20); + OUT_RING(5 << STORE_DWORD_INDEX_SHIFT); OUT_RING(dev_priv->counter); OUT_RING(0); ADVANCE_LP_RING(); @@ -715,9 +747,19 @@ void i915_dispatch_flip(struct drm_device * dev, int planes, int sync) int i915_quiescent(struct drm_device *dev) { drm_i915_private_t *dev_priv = dev->dev_private; + int ret; i915_kernel_lost_context(dev); - return i915_wait_ring(dev, dev_priv->ring.Size - 8, __FUNCTION__); + ret = i915_wait_ring(dev, dev_priv->ring.Size - 8, __FUNCTION__); + if (ret) + { + i915_kernel_lost_context (dev); + DRM_ERROR ("not quiescent head %08x tail %08x space %08x\n", + dev_priv->ring.head, + dev_priv->ring.tail, + dev_priv->ring.space); + } + return ret; } static int i915_flush_ioctl(struct drm_device *dev, void *data, @@ -1026,6 +1068,7 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags) memset(dev_priv, 0, sizeof(drm_i915_private_t)); dev->dev_private = (void *)dev_priv; + dev_priv->dev = dev; /* Add register map (needed for suspend/resume) */ base = drm_get_resource_start(dev, mmio_bar); @@ -1034,6 +1077,14 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags) ret = drm_addmap(dev, base, size, _DRM_REGISTERS, _DRM_KERNEL | _DRM_DRIVER, &dev_priv->mmio_map); + INIT_LIST_HEAD(&dev_priv->mm.active_list); + INIT_LIST_HEAD(&dev_priv->mm.flushing_list); + INIT_LIST_HEAD(&dev_priv->mm.inactive_list); + INIT_LIST_HEAD(&dev_priv->mm.request_list); + INIT_WORK(&dev_priv->user_interrupt_task, + i915_user_interrupt_handler); + dev_priv->mm.next_gem_seqno = 1; + #ifdef __linux__ #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,25) intel_init_chipset_flush_compat(dev); @@ -1074,6 +1125,7 @@ void i915_driver_lastclose(struct drm_device * dev) dev_priv->val_bufs = NULL; } #endif + i915_gem_lastclose(dev); if (drm_getsarea(dev) && dev_priv->sarea_priv) i915_do_cleanup_pageflip(dev); @@ -1125,6 +1177,11 @@ struct drm_ioctl_desc i915_ioctls[] = { #ifdef I915_HAVE_BUFFER DRM_IOCTL_DEF(DRM_I915_EXECBUFFER, i915_execbuffer, DRM_AUTH), #endif + DRM_IOCTL_DEF(DRM_I915_GEM_INIT, i915_gem_init_ioctl, DRM_AUTH), + DRM_IOCTL_DEF(DRM_I915_GEM_EXECBUFFER, i915_gem_execbuffer, DRM_AUTH), + DRM_IOCTL_DEF(DRM_I915_GEM_PIN, i915_gem_pin_ioctl, DRM_AUTH|DRM_ROOT_ONLY), + DRM_IOCTL_DEF(DRM_I915_GEM_UNPIN, i915_gem_unpin_ioctl, DRM_AUTH|DRM_ROOT_ONLY), + DRM_IOCTL_DEF(DRM_I915_GEM_BUSY, i915_gem_busy_ioctl, DRM_AUTH), }; int i915_max_ioctl = DRM_ARRAY_SIZE(i915_ioctls); |