diff options
-rw-r--r-- | linux-core/drm_compat.h | 7 | ||||
-rw-r--r-- | linux-core/drm_fence.c | 75 | ||||
-rw-r--r-- | linux-core/i915_fence.c | 18 |
3 files changed, 57 insertions, 43 deletions
diff --git a/linux-core/drm_compat.h b/linux-core/drm_compat.h index 9692492d..7741714a 100644 --- a/linux-core/drm_compat.h +++ b/linux-core/drm_compat.h @@ -152,6 +152,13 @@ static __inline__ void *kcalloc(size_t nmemb, size_t size, int flags) (tmp);}) #endif +#ifndef list_for_each_entry_safe_reverse +#define list_for_each_entry_safe_reverse(pos, n, head, member) \ + for (pos = list_entry((head)->prev, typeof(*pos), member), \ + n = list_entry(pos->member.prev, typeof(*pos), member); \ + &pos->member != (head); \ + pos = n, n = list_entry(n->member.prev, typeof(*n), member)) +#endif #include <linux/mm.h> #include <asm/page.h> diff --git a/linux-core/drm_fence.c b/linux-core/drm_fence.c index 3e17a16d..6dd04a35 100644 --- a/linux-core/drm_fence.c +++ b/linux-core/drm_fence.c @@ -43,10 +43,29 @@ void drm_fence_handler(drm_device_t * dev, uint32_t class, drm_fence_manager_t *fm = &dev->fm; drm_fence_class_manager_t *fc = &fm->class[class]; drm_fence_driver_t *driver = dev->driver->fence_driver; - struct list_head *list, *prev; - drm_fence_object_t *fence; + struct list_head *head; + drm_fence_object_t *fence, *next; int found = 0; + int is_exe = (type & DRM_FENCE_TYPE_EXE); + int ge_last_exe; + + + + diff = (sequence - fc->exe_flush_sequence) & driver->sequence_mask; + + if (fc->pending_exe_flush && is_exe && diff < driver->wrap_diff) + fc->pending_exe_flush = 0; + + diff = (sequence - fc->last_exe_flush) & driver->sequence_mask; + ge_last_exe = diff < driver->wrap_diff; + + if (ge_last_exe) + fc->pending_flush &= ~type; + if (is_exe && ge_last_exe) { + fc->last_exe_flush = sequence; + } + if (list_empty(&fc->ring)) return; @@ -58,11 +77,11 @@ void drm_fence_handler(drm_device_t * dev, uint32_t class, } } - list = (found) ? fence->ring.prev : fc->ring.prev; - prev = list->prev; + head = (found) ? &fence->ring : &fc->ring; - for (; list != &fc->ring; list = prev, prev = list->prev) { - fence = list_entry(list, drm_fence_object_t, ring); + list_for_each_entry_safe_reverse(fence, next, head, ring) { + if (&fence->ring == &fc->ring) + break; type |= fence->native_type; relevant = type & fence->type; @@ -90,12 +109,7 @@ void drm_fence_handler(drm_device_t * dev, uint32_t class, } } - - fc->pending_flush &= ~type; - if (fc->pending_exe_flush && (type & DRM_FENCE_TYPE_EXE) && - ((sequence - fc->exe_flush_sequence) < driver->wrap_diff)) - fc->pending_exe_flush = 0; - + if (wake) { DRM_WAKEUP(&fc->fence_queue); } @@ -178,24 +192,6 @@ static void drm_fence_flush_exe(drm_fence_class_manager_t * fc, uint32_t diff; if (!fc->pending_exe_flush) { - struct list_head *list; - - /* - * Last_exe_flush is invalid. Find oldest sequence. - */ - - list = &fc->ring; - if (list_empty(list)) { - return; - } else { - drm_fence_object_t *fence = - list_entry(list->next, drm_fence_object_t, ring); - fc->last_exe_flush = (fence->sequence - 1) & - driver->sequence_mask; - } - diff = (sequence - fc->last_exe_flush) & driver->sequence_mask; - if (diff >= driver->wrap_diff) - return; fc->exe_flush_sequence = sequence; fc->pending_exe_flush = 1; } else { @@ -261,14 +257,24 @@ void drm_fence_flush_old(drm_device_t * dev, uint32_t class, uint32_t sequence) drm_fence_object_t *fence; uint32_t diff; + write_lock_irqsave(&fm->lock, flags); + old_sequence = (sequence - driver->flush_diff) & driver->sequence_mask; + diff = (old_sequence - fc->last_exe_flush) & driver->sequence_mask; + + if ((diff < driver->wrap_diff) && !fc->pending_exe_flush) { + fc->pending_exe_flush = 1; + fc->exe_flush_sequence = sequence - (driver->flush_diff / 2); + } + write_unlock_irqrestore(&fm->lock, flags); + mutex_lock(&dev->struct_mutex); read_lock_irqsave(&fm->lock, flags); - if (fc->ring.next == &fc->ring) { + + if (list_empty(&fc->ring)) { read_unlock_irqrestore(&fm->lock, flags); mutex_unlock(&dev->struct_mutex); return; } - old_sequence = (sequence - driver->flush_diff) & driver->sequence_mask; fence = list_entry(fc->ring.next, drm_fence_object_t, ring); atomic_inc(&fence->usage); mutex_unlock(&dev->struct_mutex); @@ -384,6 +390,7 @@ int drm_fence_object_emit(drm_device_t * dev, drm_fence_object_t * fence, { drm_fence_manager_t *fm = &dev->fm; drm_fence_driver_t *driver = dev->driver->fence_driver; + drm_fence_class_manager_t *fc = &fm->class[fence->class]; unsigned long flags; uint32_t sequence; uint32_t native_type; @@ -402,7 +409,9 @@ int drm_fence_object_emit(drm_device_t * dev, drm_fence_object_t * fence, fence->signaled = 0x00; fence->sequence = sequence; fence->native_type = native_type; - list_add_tail(&fence->ring, &fm->class[class].ring); + if (list_empty(&fc->ring)) + fc->last_exe_flush = sequence - 1; + list_add_tail(&fence->ring, &fc->ring); write_unlock_irqrestore(&fm->lock, flags); return 0; } diff --git a/linux-core/i915_fence.c b/linux-core/i915_fence.c index 81d9b176..88daa57c 100644 --- a/linux-core/i915_fence.c +++ b/linux-core/i915_fence.c @@ -49,6 +49,7 @@ static void i915_perform_flush(drm_device_t * dev) uint32_t i_status; uint32_t diff; uint32_t sequence; + int rwflush; if (!dev_priv) return; @@ -65,14 +66,10 @@ static void i915_perform_flush(drm_device_t * dev) drm_fence_handler(dev, 0, sequence, DRM_FENCE_TYPE_EXE); } - diff = sequence - fc->exe_flush_sequence; - if (diff < driver->wrap_diff) { - fc->pending_exe_flush = 0; - if (dev_priv->fence_irq_on) { - i915_user_irq_off(dev_priv); - dev_priv->fence_irq_on = 0; - } - } else if (!dev_priv->fence_irq_on) { + if (dev_priv->fence_irq_on && !fc->pending_exe_flush) { + i915_user_irq_off(dev_priv); + dev_priv->fence_irq_on = 0; + } else if (!dev_priv->fence_irq_on && fc->pending_exe_flush) { i915_user_irq_on(dev_priv); dev_priv->fence_irq_on = 1; } @@ -89,13 +86,14 @@ static void i915_perform_flush(drm_device_t * dev) } } - if (fc->pending_flush && !dev_priv->flush_pending) { + rwflush = fc->pending_flush & DRM_I915_FENCE_TYPE_RW; + if (rwflush && !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 = 0; + fc->pending_flush &= ~DRM_I915_FENCE_TYPE_RW; } if (dev_priv->flush_pending) { |