summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--linux-core/drm_compat.h7
-rw-r--r--linux-core/drm_fence.c75
-rw-r--r--linux-core/i915_fence.c18
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) {