From a0ebcbe9d490c3e1fb8212d52e6783b7d9bd9a70 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Mon, 23 Jun 2008 00:53:04 -0700 Subject: [intel] allow the irq code to use either enable or mask registers still not sure which works best on which hardware; this will make it easier to experiment. --- shared-core/i915_drv.h | 2 + shared-core/i915_irq.c | 128 +++++++++++++++++++++++++++++++++++-------------- 2 files changed, 94 insertions(+), 36 deletions(-) diff --git a/shared-core/i915_drv.h b/shared-core/i915_drv.h index 9f500330..82d2c50c 100644 --- a/shared-core/i915_drv.h +++ b/shared-core/i915_drv.h @@ -129,6 +129,8 @@ typedef struct drm_i915_private { int user_irq_refcount; int fence_irq_on; uint32_t irq_mask_reg; + uint32_t irq_enable_reg; + int irq_use_mask; int irq_enabled; #ifdef I915_HAVE_FENCE diff --git a/shared-core/i915_irq.c b/shared-core/i915_irq.c index a55497a8..6dbc12e4 100644 --- a/shared-core/i915_irq.c +++ b/shared-core/i915_irq.c @@ -40,6 +40,63 @@ I915_DISPLAY_PIPE_A_EVENT_INTERRUPT | \ I915_DISPLAY_PIPE_B_EVENT_INTERRUPT) +static inline void +i915_enable_irq(drm_i915_private_t *dev_priv, uint32_t mask) +{ + if (dev_priv->irq_use_mask) { + if ((dev_priv->irq_mask_reg & mask) != 0) { + dev_priv->irq_mask_reg &= ~mask; + I915_WRITE(I915REG_INT_MASK_R, dev_priv->irq_mask_reg); + (void) I915_READ(I915REG_INT_MASK_R); + } + } else { + if ((dev_priv->irq_enable_reg & mask) != mask) { + dev_priv->irq_enable_reg |= mask; + I915_WRITE(I915REG_INT_ENABLE_R, dev_priv->irq_enable_reg); + (void) I915_READ(I915REG_INT_ENABLE_R); + } + } +} + +static inline void +i915_disable_irq(drm_i915_private_t *dev_priv, uint32_t mask) +{ + if (dev_priv->irq_use_mask) { + if ((dev_priv->irq_enable_reg & mask) != mask) { + dev_priv->irq_mask_reg |= mask; + I915_WRITE(I915REG_INT_MASK_R, dev_priv->irq_mask_reg); + (void) I915_READ(I915REG_INT_MASK_R); + } + } else { + if ((dev_priv->irq_enable_reg & mask) != 0) { + dev_priv->irq_enable_reg &= ~mask; + I915_WRITE(I915REG_INT_ENABLE_R, dev_priv->irq_enable_reg); + (void) I915_READ(I915REG_INT_ENABLE_R); + } + } +} + +static inline void +i915_enable_irqs(drm_i915_private_t *dev_priv) +{ + if (dev_priv->irq_use_mask) { + I915_WRITE(I915REG_INT_MASK_R, dev_priv->irq_mask_reg); + (void) I915_READ(I915REG_INT_MASK_R); + } else { + I915_WRITE(I915REG_INT_ENABLE_R, dev_priv->irq_enable_reg); + (void) I915_READ(I915REG_INT_ENABLE_R); + } +} + +static inline void +i915_disable_irqs(drm_i915_private_t *dev_priv) +{ + if (dev_priv->irq_use_mask) + I915_WRITE(I915REG_INT_MASK_R, I915_INTERRUPT_ENABLE_MASK); + else + I915_WRITE(I915REG_INT_ENABLE_R, 0); +} + /** * i915_get_pipe - return the the pipe associated with a given plane * @dev: DRM device @@ -450,8 +507,9 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS) u32 pipea_stats = 0, pipeb_stats = 0; int vblank = 0; - if (dev->pdev->msi_enabled) - I915_WRITE(I915REG_INT_MASK_R, ~0); + DRM_SPINLOCK(&dev_priv->user_irq_lock); +// if (dev->pdev->msi_enabled) + i915_disable_irqs(dev_priv); iir = I915_READ(I915REG_INT_IDENTITY_R); #if 0 DRM_DEBUG("flag=%08x\n", iir); @@ -464,11 +522,10 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS) I915_READ(I915REG_INT_ENABLE_R), I915_READ(I915REG_PIPEASTAT), I915_READ(I915REG_PIPEBSTAT)); - if (dev->pdev->msi_enabled) { - I915_WRITE(I915REG_INT_MASK_R, - dev_priv->irq_mask_reg); - (void) I915_READ(I915REG_INT_MASK_R); - } +// if (dev->pdev->msi_enabled) + i915_enable_irqs(dev_priv); + + DRM_SPINUNLOCK(&dev_priv->user_irq_lock); return IRQ_NONE; } @@ -486,10 +543,13 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS) } I915_WRITE(I915REG_INT_IDENTITY_R, iir); - if (dev->pdev->msi_enabled) - I915_WRITE(I915REG_INT_MASK_R, dev_priv->irq_mask_reg); (void) I915_READ(I915REG_INT_IDENTITY_R); /* Flush posted writes */ +// if (dev->pdev->msi_enabled) + i915_enable_irqs(dev_priv); + + DRM_SPINUNLOCK(&dev_priv->user_irq_lock); + if (dev_priv->sarea_priv) dev_priv->sarea_priv->last_dispatch = READ_BREADCRUMB(dev_priv); @@ -541,14 +601,8 @@ int i915_emit_irq(struct drm_device *dev) void i915_user_irq_on(drm_i915_private_t *dev_priv) { DRM_SPINLOCK(&dev_priv->user_irq_lock); - if (dev_priv->irq_enabled && (++dev_priv->user_irq_refcount == 1)){ - if ((dev_priv->irq_mask_reg & I915_USER_INTERRUPT) != 0) { - dev_priv->irq_mask_reg &= ~I915_USER_INTERRUPT; - I915_WRITE(I915REG_INT_MASK_R, dev_priv->irq_mask_reg); - I915_WRITE(I915REG_INT_IDENTITY_R, I915_USER_INTERRUPT); - (void) I915_READ (I915REG_INT_MASK_R); - } - } + if (dev_priv->irq_enabled && (++dev_priv->user_irq_refcount == 1)) + i915_enable_irq(dev_priv, I915_USER_INTERRUPT); DRM_SPINUNLOCK(&dev_priv->user_irq_lock); } @@ -557,13 +611,8 @@ void i915_user_irq_off(drm_i915_private_t *dev_priv) { DRM_SPINLOCK(&dev_priv->user_irq_lock); BUG_ON(dev_priv->irq_enabled && dev_priv->user_irq_refcount <= 0); - if (dev_priv->irq_enabled && (--dev_priv->user_irq_refcount == 0)) { - if ((dev_priv->irq_mask_reg & I915_USER_INTERRUPT) == 0) { - dev_priv->irq_mask_reg |= I915_USER_INTERRUPT; - I915_WRITE(I915REG_INT_MASK_R, dev_priv->irq_mask_reg); - (void) I915_READ(I915REG_INT_MASK_R); - } - } + if (dev_priv->irq_enabled && (--dev_priv->user_irq_refcount == 0)) + i915_disable_irq(dev_priv, I915_USER_INTERRUPT); DRM_SPINUNLOCK(&dev_priv->user_irq_lock); } @@ -688,9 +737,7 @@ int i915_enable_vblank(struct drm_device *dev, int plane) I915_WRITE(pipestat_reg, pipestat); } DRM_SPINLOCK(&dev_priv->user_irq_lock); - dev_priv->irq_mask_reg &= ~mask_reg; - I915_WRITE(I915REG_INT_MASK_R, dev_priv->irq_mask_reg); - I915_READ(I915REG_INT_MASK_R); + i915_enable_irq(dev_priv, mask_reg); DRM_SPINUNLOCK(&dev_priv->user_irq_lock); return 0; @@ -720,10 +767,7 @@ void i915_disable_vblank(struct drm_device *dev, int plane) } DRM_SPINLOCK(&dev_priv->user_irq_lock); - dev_priv->irq_mask_reg |= mask_reg; - I915_WRITE(I915REG_INT_MASK_R, dev_priv->irq_mask_reg); - (void) I915_READ (I915REG_INT_MASK_R); - DRM_SPINUNLOCK(&dev_priv->user_irq_lock); + i915_disable_irq(dev_priv, mask_reg); if (pipestat_reg) { pipestat = I915_READ (pipestat_reg); @@ -737,15 +781,24 @@ void i915_disable_vblank(struct drm_device *dev, int plane) I915_WRITE(pipestat_reg, pipestat); (void) I915_READ(pipestat_reg); } + DRM_SPINUNLOCK(&dev_priv->user_irq_lock); } static void i915_enable_interrupt (struct drm_device *dev) { drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; - dev_priv->irq_mask_reg = ~0; + dev_priv->irq_use_mask = 0; + if (dev_priv->irq_use_mask) { + dev_priv->irq_mask_reg = I915_INTERRUPT_ENABLE_MASK; + dev_priv->irq_enable_reg = I915_INTERRUPT_ENABLE_MASK; + } else { + dev_priv->irq_mask_reg = 0; + dev_priv->irq_enable_reg = 0; + } + I915_WRITE(I915REG_INT_IDENTITY_R, I915_READ(I915REG_INT_IDENTITY_R)); I915_WRITE(I915REG_INT_MASK_R, dev_priv->irq_mask_reg); - I915_WRITE(I915REG_INT_ENABLE_R, I915_INTERRUPT_ENABLE_MASK); + I915_WRITE(I915REG_INT_ENABLE_R, dev_priv->irq_enable_reg); (void) I915_READ (I915REG_INT_ENABLE_R); dev_priv->irq_enabled = 1; } @@ -755,9 +808,9 @@ static void i915_disable_interrupt (struct drm_device *dev) drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; I915_WRITE(I915REG_HWSTAM, 0xffffffff); - I915_WRITE(I915REG_INT_MASK_R, 0xffffffff); + I915_WRITE(I915REG_INT_MASK_R, I915_INTERRUPT_ENABLE_MASK); I915_WRITE(I915REG_INT_ENABLE_R, 0); - I915_WRITE(I915REG_INT_IDENTITY_R, 0xffffffff); + I915_WRITE(I915REG_INT_IDENTITY_R, I915_READ(I915REG_INT_IDENTITY_R)); (void) I915_READ (I915REG_INT_IDENTITY_R); dev_priv->irq_enabled = 0; } @@ -797,7 +850,10 @@ int i915_vblank_pipe_get(struct drm_device *dev, void *data, return -EINVAL; } - flag = I915_READ(I915REG_INT_ENABLE_R); + if (dev_priv->irq_use_mask) + flag = ~dev_priv->irq_mask_reg; + else + flag = dev_priv->irq_enable_reg; pipe->pipe = 0; if (flag & I915_DISPLAY_PIPE_A_EVENT_INTERRUPT) pipe->pipe |= DRM_I915_VBLANK_PIPE_A; -- cgit v1.2.3 From 61caf797aeb88af42ea0d333ad3f6ba88468d37f Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Mon, 23 Jun 2008 00:53:53 -0700 Subject: [intel-gem] pwrite through GTT Pin/copy_from_user/unpin through the GTT to eliminate clflush costs. Benchmarks say this helps quite a bit. --- linux-core/i915_gem.c | 158 +++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 125 insertions(+), 33 deletions(-) diff --git a/linux-core/i915_gem.c b/linux-core/i915_gem.c index 4361b060..4dfbd2a1 100644 --- a/linux-core/i915_gem.c +++ b/linux-core/i915_gem.c @@ -36,7 +36,14 @@ #define WATCH_LRU 0 #define WATCH_RELOC 0 #define WATCH_INACTIVE 0 +#define WATCH_PWRITE 0 +#if WATCH_BUF | WATCH_EXEC | WATCH_PWRITE +static void +i915_gem_dump_object(struct drm_gem_object *obj, int len, + const char *where, uint32_t mark); +#endif + static int i915_gem_object_set_domain(struct drm_gem_object *obj, uint32_t read_domains, @@ -154,6 +161,8 @@ i915_gem_pread_ioctl(struct drm_device *dev, void *data, return 0; } +#include "drm_compat.h" + /** * Writes data to the object referenced by handle. * @@ -165,41 +174,121 @@ i915_gem_pwrite_ioctl(struct drm_device *dev, void *data, { struct drm_i915_gem_pwrite *args = data; struct drm_gem_object *obj; - ssize_t written; + struct drm_i915_gem_object *obj_priv; + ssize_t remain; loff_t offset; - int ret; + char __user *user_data; + char *vaddr; + int i, o, l; + int ret = 0; + unsigned long pfn; + unsigned long unwritten; obj = drm_gem_object_lookup(dev, file_priv, args->handle); if (obj == NULL) return -EINVAL; + /** Bounds check destination. + * + * XXX: This could use review for overflow issues... + */ + if (args->offset > obj->size || args->size > obj->size || + args->offset + args->size > obj->size) + return -EFAULT; + + user_data = (char __user *) (uintptr_t) args->data_ptr; + remain = args->size; + if (!access_ok(VERIFY_READ, user_data, remain)) + return -EFAULT; + + mutex_lock(&dev->struct_mutex); - ret = i915_gem_set_domain(obj, file_priv, - I915_GEM_DOMAIN_CPU, I915_GEM_DOMAIN_CPU); + ret = i915_gem_object_pin(obj, 0); if (ret) { drm_gem_object_unreference(obj); mutex_unlock(&dev->struct_mutex); return ret; } - offset = args->offset; + ret = i915_gem_set_domain(obj, file_priv, + I915_GEM_DOMAIN_GTT, I915_GEM_DOMAIN_GTT); + if (ret) + goto fail; + + obj_priv = obj->driver_private; + offset = obj_priv->gtt_offset + args->offset; + obj_priv->dirty = 1; + + while (remain > 0) { + + /** Operation in this page + * + * i = page number + * o = offset within page + * l = bytes to copy + */ + i = offset >> PAGE_SHIFT; + o = offset & (PAGE_SIZE-1); + l = remain; + if ((o + l) > PAGE_SIZE) + l = PAGE_SIZE - o; + + pfn = (dev->agp->base >> PAGE_SHIFT) + i; + +#ifdef DRM_KMAP_ATOMIC_PROT_PFN + /* kmap_atomic can't map IO pages on non-HIGHMEM kernels + */ + vaddr = kmap_atomic_prot_pfn(pfn, KM_USER0, + __pgprot(__PAGE_KERNEL)); +#if WATCH_PWRITE + DRM_INFO("pwrite i %d o %d l %d pfn %ld vaddr %p\n", + i, o, l, pfn, vaddr); +#endif + unwritten = __copy_from_user_inatomic_nocache(vaddr + o, user_data, l); + kunmap_atomic(vaddr, KM_USER0); - written = vfs_write(obj->filp, - (char __user *)(uintptr_t) args->data_ptr, - args->size, &offset); + if (unwritten) +#endif + { + vaddr = ioremap(pfn << PAGE_SHIFT, PAGE_SIZE); +#if WATCH_PWRITE + DRM_INFO("pwrite slow i %d o %d l %d pfn %ld vaddr %p\n", + i, o, l, pfn, vaddr); +#endif + if (vaddr == NULL) { + ret = -EFAULT; + goto fail; + } + unwritten = __copy_from_user(vaddr + o, user_data, l); +#if WATCH_PWRITE + DRM_INFO("unwritten %ld\n", unwritten); +#endif + iounmap(vaddr); + if (unwritten) { + ret = -EFAULT; + goto fail; + } + } - if (written != args->size) { - drm_gem_object_unreference(obj); - mutex_unlock(&dev->struct_mutex); - if (written < 0) - return written; - else - return -EINVAL; + remain -= l; + user_data += l; + offset += l; } +#if WATCH_PWRITE && 1 + i915_gem_clflush_object(obj); + i915_gem_dump_object(obj, args->offset + args->size, __func__, ~0); + i915_gem_clflush_object(obj); +#endif +fail: + i915_gem_object_unpin (obj); drm_gem_object_unreference(obj); mutex_unlock(&dev->struct_mutex); - return 0; +#if WATCH_PWRITE + if (ret) + DRM_INFO("pwrite failed %d\n", ret); +#endif + return ret; } /** @@ -361,7 +450,7 @@ i915_verify_inactive(struct drm_device *dev, char *file, int line) list_for_each_entry(obj_priv, &dev_priv->mm.inactive_list, list) { obj = obj_priv->obj; - if (obj_priv->pin_count || obj_priv->active || (obj->write_domain & ~I915_GEM_DOMAIN_CPU)) + if (obj_priv->pin_count || obj_priv->active || (obj->write_domain & ~(I915_GEM_DOMAIN_CPU|I915_GEM_DOMAIN_GTT)) DRM_ERROR("inactive %p (p %d a %d w %x) %s:%d\n", obj, obj_priv->pin_count, obj_priv->active, obj->write_domain, file, line); @@ -644,7 +733,7 @@ i915_gem_flush(struct drm_device *dev, if (flush_domains & I915_GEM_DOMAIN_CPU) drm_agp_chipset_flush(dev); - if ((invalidate_domains|flush_domains) & ~I915_GEM_DOMAIN_CPU) { + if ((invalidate_domains|flush_domains) & ~(I915_GEM_DOMAIN_CPU|I915_GEM_DOMAIN_GTT)) { /* * read/write caches: * @@ -712,7 +801,7 @@ i915_gem_object_wait_rendering(struct drm_gem_object *obj) /* If there are writes queued to the buffer, flush and * create a new seqno to wait for. */ - if (obj->write_domain & ~(I915_GEM_DOMAIN_CPU)) { + if (obj->write_domain & ~(I915_GEM_DOMAIN_CPU|I915_GEM_DOMAIN_GTT)) { uint32_t write_domain = obj->write_domain; #if WATCH_BUF DRM_INFO("%s: flushing object %p from write domain %08x\n", @@ -798,11 +887,13 @@ i915_gem_object_unbind(struct drm_gem_object *obj) i915_gem_object_free_page_list(obj); - atomic_dec(&dev->gtt_count); - atomic_sub(obj->size, &dev->gtt_memory); - - drm_memrange_put_block(obj_priv->gtt_space); - obj_priv->gtt_space = NULL; + if (obj_priv->gtt_space) { + atomic_dec(&dev->gtt_count); + atomic_sub(obj->size, &dev->gtt_memory); + + drm_memrange_put_block(obj_priv->gtt_space); + obj_priv->gtt_space = NULL; + } /* Remove ourselves from the LRU list if present. */ if (!list_empty(&obj_priv->list)) @@ -811,7 +902,7 @@ i915_gem_object_unbind(struct drm_gem_object *obj) return 0; } -#if WATCH_BUF | WATCH_EXEC +#if WATCH_BUF | WATCH_EXEC | WATCH_PWRITE static void i915_gem_dump_page(struct page *page, uint32_t start, uint32_t end, uint32_t bias, uint32_t mark) @@ -1105,8 +1196,8 @@ i915_gem_object_bind_to_gtt(struct drm_gem_object *obj, unsigned alignment) * wasn't in the GTT, there shouldn't be any way it could have been in * a GPU cache */ - BUG_ON(obj->read_domains & ~I915_GEM_DOMAIN_CPU); - BUG_ON(obj->write_domain & ~I915_GEM_DOMAIN_CPU); + BUG_ON(obj->read_domains & ~(I915_GEM_DOMAIN_CPU|I915_GEM_DOMAIN_GTT)); + BUG_ON(obj->write_domain & ~(I915_GEM_DOMAIN_CPU|I915_GEM_DOMAIN_GTT)); return 0; } @@ -1289,7 +1380,7 @@ i915_gem_object_set_domain(struct drm_gem_object *obj, * flushed before the cpu cache is invalidated */ if ((invalidate_domains & I915_GEM_DOMAIN_CPU) && - (flush_domains & ~I915_GEM_DOMAIN_CPU)) { + (flush_domains & ~(I915_GEM_DOMAIN_CPU|I915_GEM_DOMAIN_GTT))) { ret = i915_gem_object_wait_rendering(obj); if (ret) return ret; @@ -1911,7 +2002,7 @@ i915_gem_object_pin(struct drm_gem_object *obj, uint32_t alignment) if (obj_priv->pin_count == 1) { atomic_inc(&dev->pin_count); atomic_add(obj->size, &dev->pin_memory); - if (!obj_priv->active && (obj->write_domain & ~I915_GEM_DOMAIN_CPU) == 0 && + if (!obj_priv->active && (obj->write_domain & ~(I915_GEM_DOMAIN_CPU|I915_GEM_DOMAIN_GTT)) == 0 && !list_empty(&obj_priv->list)) list_del_init(&obj_priv->list); } @@ -1937,7 +2028,7 @@ i915_gem_object_unpin(struct drm_gem_object *obj) * the inactive list */ if (obj_priv->pin_count == 0) { - if (!obj_priv->active && (obj->write_domain & ~I915_GEM_DOMAIN_CPU) == 0) + if (!obj_priv->active && (obj->write_domain & ~(I915_GEM_DOMAIN_CPU|I915_GEM_DOMAIN_GTT)) == 0) list_move_tail(&obj_priv->list, &dev_priv->mm.inactive_list); atomic_dec(&dev->pin_count); @@ -2096,7 +2187,7 @@ i915_gem_set_domain(struct drm_gem_object *obj, return ret; flush_domains = i915_gem_dev_set_domain(obj->dev); - if (flush_domains & ~I915_GEM_DOMAIN_CPU) + if (flush_domains & ~(I915_GEM_DOMAIN_CPU|I915_GEM_DOMAIN_GTT)) (void) i915_add_request(dev, flush_domains); return 0; @@ -2154,8 +2245,9 @@ i915_gem_idle(struct drm_device *dev) /* Flush the GPU along with all non-CPU write domains */ - i915_gem_flush(dev, ~I915_GEM_DOMAIN_CPU, ~I915_GEM_DOMAIN_CPU); - seqno = i915_add_request(dev, ~I915_GEM_DOMAIN_CPU); + i915_gem_flush(dev, ~(I915_GEM_DOMAIN_CPU|I915_GEM_DOMAIN_GTT), + ~(I915_GEM_DOMAIN_CPU|I915_GEM_DOMAIN_GTT)); + seqno = i915_add_request(dev, ~(I915_GEM_DOMAIN_CPU|I915_GEM_DOMAIN_GTT)); if (seqno == 0) { mutex_unlock(&dev->struct_mutex); -- cgit v1.2.3 From 1c2dd9826793579d5ef6f51fb9f5470c4af95548 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Mon, 23 Jun 2008 10:07:47 -0700 Subject: [intel] Switch to using IMR instead of IER --- shared-core/i915_irq.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/shared-core/i915_irq.c b/shared-core/i915_irq.c index 6dbc12e4..6f1d91b3 100644 --- a/shared-core/i915_irq.c +++ b/shared-core/i915_irq.c @@ -788,7 +788,7 @@ static void i915_enable_interrupt (struct drm_device *dev) { drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; - dev_priv->irq_use_mask = 0; + dev_priv->irq_use_mask = 1; if (dev_priv->irq_use_mask) { dev_priv->irq_mask_reg = I915_INTERRUPT_ENABLE_MASK; dev_priv->irq_enable_reg = I915_INTERRUPT_ENABLE_MASK; -- cgit v1.2.3 From 626e9ba494b46f6e8352c9e461227187f335e229 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Mon, 23 Jun 2008 10:16:35 -0700 Subject: [intel-gem] Recover resources from wedged hardware. Clean up queues, free objects. On the next entervt, unmark the hardware to let the user try again (presumably after resetting the chip). Someday we'll automatically recover... --- linux-core/i915_gem.c | 23 +++++++++++++++++++++-- shared-core/i915_drv.h | 9 +++++++++ 2 files changed, 30 insertions(+), 2 deletions(-) diff --git a/linux-core/i915_gem.c b/linux-core/i915_gem.c index 4dfbd2a1..16a1b07e 100644 --- a/linux-core/i915_gem.c +++ b/linux-core/i915_gem.c @@ -653,7 +653,7 @@ i915_gem_retire_requests(struct drm_device *dev) list); retiring_seqno = request->seqno; - if (i915_seqno_passed(seqno, retiring_seqno)) { + if (i915_seqno_passed(seqno, retiring_seqno) || dev_priv->mm.wedged) { i915_gem_retire_request(dev, request); list_del(&request->list); @@ -697,10 +697,13 @@ i915_wait_request(struct drm_device *dev, uint32_t seqno) i915_user_irq_on(dev_priv); ret = wait_event_interruptible(dev_priv->irq_queue, i915_seqno_passed(i915_get_gem_seqno(dev), - seqno)); + seqno) || dev_priv->mm.wedged); i915_user_irq_off(dev_priv); dev_priv->mm.waiting_gem_seqno = 0; } + if (dev_priv->mm.wedged) + ret = -EIO; + if (ret) DRM_ERROR("%s returns %d (awaiting %d at %d)\n", __func__, ret, seqno, i915_get_gem_seqno(dev)); @@ -1019,6 +1022,8 @@ i915_gem_evict_something(struct drm_device *dev) list); ret = i915_wait_request(dev, request->seqno); + if (ret) + break; /* if waiting caused an object to become inactive, * then loop around and wait for it. Otherwise, we @@ -1822,6 +1827,13 @@ i915_gem_execbuffer(struct drm_device *dev, void *data, mutex_lock(&dev->struct_mutex); i915_verify_inactive(dev, __FILE__, __LINE__); + + if (dev_priv->mm.wedged) { + DRM_ERROR("Execbuf while wedged\n"); + mutex_unlock(&dev->struct_mutex); + return -EIO; + } + if (dev_priv->mm.suspended) { DRM_ERROR("Execbuf while VT-switched.\n"); mutex_unlock(&dev->struct_mutex); @@ -2264,6 +2276,8 @@ i915_gem_idle(struct drm_device *dev) if (last_seqno == cur_seqno) { if (stuck++ > 100) { DRM_ERROR("hardware wedged\n"); + dev_priv->mm.wedged = 1; + DRM_WAKEUP(&dev_priv->irq_queue); break; } } @@ -2378,6 +2392,11 @@ i915_gem_entervt_ioctl(struct drm_device *dev, void *data, drm_i915_private_t *dev_priv = dev->dev_private; int ret; + if (dev_priv->mm.wedged) { + DRM_ERROR("Renabling wedged hardware, good luck\n"); + dev_priv->mm.wedged = 0; + } + ret = i915_gem_init_ringbuffer(dev); if (ret != 0) return ret; diff --git a/shared-core/i915_drv.h b/shared-core/i915_drv.h index 82d2c50c..a8d5b91e 100644 --- a/shared-core/i915_drv.h +++ b/shared-core/i915_drv.h @@ -309,6 +309,15 @@ typedef struct drm_i915_private { * transitioned away from for kernel modesetting. */ int suspended; + + /** + * Flag if the hardware appears to be wedged. + * + * This is set when attempts to idle the device timeout. + * It prevents command submission from occuring and makes + * every pending request fail + */ + int wedged; } mm; } drm_i915_private_t; -- cgit v1.2.3 From 27f61d0c9364bbf8bc88a4ffceb78b645aff6680 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Mon, 23 Jun 2008 11:20:17 -0700 Subject: [intel] leave interrupts disabled in ISR only on MSI again While debugging the 915, I tried this trick there and accidentally left it set. --- shared-core/i915_irq.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/shared-core/i915_irq.c b/shared-core/i915_irq.c index 6f1d91b3..23edddb1 100644 --- a/shared-core/i915_irq.c +++ b/shared-core/i915_irq.c @@ -508,7 +508,7 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS) int vblank = 0; DRM_SPINLOCK(&dev_priv->user_irq_lock); -// if (dev->pdev->msi_enabled) + if (dev->pdev->msi_enabled) i915_disable_irqs(dev_priv); iir = I915_READ(I915REG_INT_IDENTITY_R); #if 0 @@ -522,7 +522,7 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS) I915_READ(I915REG_INT_ENABLE_R), I915_READ(I915REG_PIPEASTAT), I915_READ(I915REG_PIPEBSTAT)); -// if (dev->pdev->msi_enabled) + if (dev->pdev->msi_enabled) i915_enable_irqs(dev_priv); DRM_SPINUNLOCK(&dev_priv->user_irq_lock); @@ -545,7 +545,7 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS) I915_WRITE(I915REG_INT_IDENTITY_R, iir); (void) I915_READ(I915REG_INT_IDENTITY_R); /* Flush posted writes */ -// if (dev->pdev->msi_enabled) + if (dev->pdev->msi_enabled) i915_enable_irqs(dev_priv); DRM_SPINUNLOCK(&dev_priv->user_irq_lock); -- cgit v1.2.3 From 52bf2e77b0ff77ab0c93fec374ccfeb9d214a464 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Mon, 23 Jun 2008 11:21:30 -0700 Subject: [intel-gem] Use I915_GEM_DOMAIN_GTT in dri_gem_bo_wait_rendering. I915_GEM_DOMAIN_CPU is very expensive to wait for -- it generally requires clflushing the frame buffer. --- libdrm/intel/intel_bufmgr_gem.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libdrm/intel/intel_bufmgr_gem.c b/libdrm/intel/intel_bufmgr_gem.c index b970eacf..cdc2a7ac 100644 --- a/libdrm/intel/intel_bufmgr_gem.c +++ b/libdrm/intel/intel_bufmgr_gem.c @@ -596,7 +596,7 @@ dri_gem_bo_wait_rendering(dri_bo *bo) int ret; set_domain.handle = bo_gem->gem_handle; - set_domain.read_domains = I915_GEM_DOMAIN_CPU; + set_domain.read_domains = I915_GEM_DOMAIN_GTT; set_domain.write_domain = 0; ret = ioctl (bufmgr_gem->fd, DRM_IOCTL_I915_GEM_SET_DOMAIN, &set_domain); if (ret != 0) { -- cgit v1.2.3 From 020a59e46ca1d89c98a3e309b6e5571354115133 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Mon, 23 Jun 2008 22:03:06 -0700 Subject: drm_compat: it's CONFIG_HIGHMEM, not CONFIG_HIMEM A mis-spelled config option (was it spelled that way in the past?) eliminated kmap_atomic_prot_pfn from core DRM. --- linux-core/drm_compat.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/linux-core/drm_compat.h b/linux-core/drm_compat.h index 30834f33..6aa19c55 100644 --- a/linux-core/drm_compat.h +++ b/linux-core/drm_compat.h @@ -329,7 +329,7 @@ typedef _Bool bool; #endif -#if (defined(CONFIG_X86) && defined(CONFIG_X86_32) && defined(CONFIG_HIMEM)) +#if (defined(CONFIG_X86) && defined(CONFIG_X86_32) && defined(CONFIG_HIGHMEM)) #define DRM_KMAP_ATOMIC_PROT_PFN extern void *kmap_atomic_prot_pfn(unsigned long pfn, enum km_type type, pgprot_t protection); -- cgit v1.2.3 From 472981a4a952e551a581e5296a575a51d4f02e3d Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Mon, 23 Jun 2008 22:03:33 -0700 Subject: [intel-gem] Include drm_compat.h to get kmap_atomic_prot_pfn --- linux-core/i915_gem.c | 1 + 1 file changed, 1 insertion(+) diff --git a/linux-core/i915_gem.c b/linux-core/i915_gem.c index 16a1b07e..8fd2b8a6 100644 --- a/linux-core/i915_gem.c +++ b/linux-core/i915_gem.c @@ -27,6 +27,7 @@ #include "drmP.h" #include "drm.h" +#include "drm_compat.h" #include "i915_drm.h" #include "i915_drv.h" -- cgit v1.2.3 From 01a33d742cee55a3df66a3d29c9c55b10cc9221d Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Tue, 24 Jun 2008 09:46:51 -0700 Subject: Was using irq_enable_reg in the use_mask_reg path --- shared-core/i915_irq.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/shared-core/i915_irq.c b/shared-core/i915_irq.c index 23edddb1..f9fed87e 100644 --- a/shared-core/i915_irq.c +++ b/shared-core/i915_irq.c @@ -62,7 +62,7 @@ static inline void i915_disable_irq(drm_i915_private_t *dev_priv, uint32_t mask) { if (dev_priv->irq_use_mask) { - if ((dev_priv->irq_enable_reg & mask) != mask) { + if ((dev_priv->irq_mask_reg & mask) != mask) { dev_priv->irq_mask_reg |= mask; I915_WRITE(I915REG_INT_MASK_R, dev_priv->irq_mask_reg); (void) I915_READ(I915REG_INT_MASK_R); -- cgit v1.2.3