summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas Hellstrom <thomas@tungstengraphics.com>2006-03-29 13:17:32 +0000
committerThomas Hellstrom <thomas@tungstengraphics.com>2006-03-29 13:17:32 +0000
commitb5e6a6ef50c14eb81b6b1a2a93729fa286fdea8e (patch)
treebf2ff1e28d2e1912bb9611e0658846cdd5a2a2c8
parent2ee043902e18ef52701d019117feb508500d9a58 (diff)
ttm/intel: Add means for fence ageing and eviction of old regions. libdrm:
Be paranoid and always validate buffers when told to do so.
-rw-r--r--libdrm/xf86mm.c20
-rw-r--r--linux-core/drmP.h2
-rw-r--r--linux-core/drm_ttm.c64
-rw-r--r--linux-core/i915_ttm.c2
-rw-r--r--shared-core/i915_drv.h1
-rw-r--r--shared-core/i915_irq.c15
6 files changed, 87 insertions, 17 deletions
diff --git a/libdrm/xf86mm.c b/libdrm/xf86mm.c
index b5f6ca2f..76a0a82a 100644
--- a/libdrm/xf86mm.c
+++ b/libdrm/xf86mm.c
@@ -784,7 +784,7 @@ drmCheckValidation(unsigned flags, drmMMBuf * buf)
return -1;
if (buf->flags & DRM_MM_SHARED)
return -1;
- if (buf->flags & DRM_MM_NEW)
+ if (buf->flags & DRM_MM_NEW)
return 1;
if (!FLAGS_COMPATIBLE(buf->flags, flags))
return 1;
@@ -794,7 +794,7 @@ drmCheckValidation(unsigned flags, drmMMBuf * buf)
if ((drmMMKI.sarea->evict_tt_seq - buf->block->lastValSeq - 1) <=
DRM_MM_WRAP)
return 1;
- return 0;
+ return 1;
}
static int
@@ -840,11 +840,13 @@ drmMMValidateBuffers(int drmFD, drmMMBufList * head)
unsigned flags;
drmMMCheckInit(drmFD);
+
while (cur != head) {
buf = cur->buf;
flags = cur->flags;
if (buf->pool)
flags = buf->pool->flags;
+
tmp = drmCheckValidation(flags, cur->buf);
if (tmp >= 0)
needsValid++;
@@ -853,8 +855,12 @@ drmMMValidateBuffers(int drmFD, drmMMBufList * head)
cur = cur->next;
}
- vl = NULL;
+ if (!doValid) {
+ drmMMReturnOffsets(head);
+ return 0;
+ }
+ vl = NULL;
if (needsValid) {
vl = (drm_ttm_buf_arg_t *) calloc(needsValid, sizeof(*vl));
@@ -864,16 +870,8 @@ drmMMValidateBuffers(int drmFD, drmMMBufList * head)
}
}
- if (!doValid) {
- drmMMReturnOffsets(head);
- if (vl)
- free(vl);
- return 0;
- }
-
curBArg = vl;
cur = head->next;
-
while (cur != head) {
buf = cur->buf;
block = buf->block;
diff --git a/linux-core/drmP.h b/linux-core/drmP.h
index ac67304b..bd30a461 100644
--- a/linux-core/drmP.h
+++ b/linux-core/drmP.h
@@ -599,6 +599,8 @@ typedef struct drm_mm_driver {
uint32_t fence);
int (*test_fence) (struct drm_device * dev, uint32_t type,
uint32_t fence);
+ int (*fence_aged) (struct drm_device * dev, uint32_t type,
+ uint32_t fence);
void (*flush_caches) (struct drm_device * dev, int access);
drm_ttm_backend_t *(*create_ttm_backend_entry) (struct drm_device * dev,
int cached);
diff --git a/linux-core/drm_ttm.c b/linux-core/drm_ttm.c
index 03faf5ce..561a9a4c 100644
--- a/linux-core/drm_ttm.c
+++ b/linux-core/drm_ttm.c
@@ -621,9 +621,8 @@ static int remove_ttm_region(drm_ttm_backend_list_t * entry, int ret_if_busy)
DRM_DEBUG("Nope, buf busy.\n");
return ret;
}
- }
-
- entry->mm_node = NULL;
+ }
+ entry->mm_node = NULL;
mm_node->private = NULL;
spin_lock(&mm->mm.mm_lock);
list_del(&mm_priv->lru);
@@ -633,6 +632,7 @@ static int remove_ttm_region(drm_ttm_backend_list_t * entry, int ret_if_busy)
return 0;
}
+
/*
* Unbind a ttm region from the aperture and take it out of the
* aperture manager.
@@ -1095,6 +1095,55 @@ int drm_add_ttm(drm_device_t * dev, unsigned size, drm_map_list_t ** maplist)
return 0;
}
+
+static int drm_ttm_evict_aged(drm_ttm_mm_t *mm)
+{
+ struct list_head *list;
+ spinlock_t *mm_lock = &mm->mm.mm_lock;
+ drm_ttm_mm_priv_t *evict_priv;
+ uint32_t evict_fence;
+ drm_device_t *dev = mm->dev;
+ drm_mm_node_t *evict_node;
+ int evicted = FALSE;
+
+ spin_lock(mm_lock);
+
+ do {
+ list = mm->lru_head.next;
+
+ if (list == &mm->lru_head)
+ break;
+
+ evict_priv = list_entry(list, drm_ttm_mm_priv_t, lru);
+ if (!evict_priv->fence_valid)
+ break;
+
+ evict_fence = evict_priv->fence;
+ if (!dev->mm_driver->
+ test_fence(dev, evict_priv->region->fence_type,
+ evict_fence))
+ break;
+
+ if (!dev->mm_driver->
+ fence_aged(dev, evict_priv->region->fence_type,
+ evict_fence))
+ break;
+ evicted = TRUE;
+ evict_node = evict_priv->region->mm_node;
+ drm_evict_ttm_region(evict_priv->region);
+ list_del_init(list);
+ evict_node->private = NULL;
+ drm_mm_put_block_locked(&mm->mm, evict_node);
+ evict_priv->region->mm_node = NULL;
+ drm_free(evict_priv, sizeof(*evict_priv), DRM_MEM_MM);
+ } while (TRUE);
+ spin_unlock(mm_lock);
+
+ return evicted;
+}
+
+
+
/*
* Fence all unfenced regions in the global lru list.
* FIXME: This is exported until we have a scheduler built in.
@@ -1110,6 +1159,7 @@ void drm_ttm_fence_regions(drm_device_t * dev)
uint32_t fence_type;
uint32_t fence;
drm_ttm_mm_t *mm = &dev->mm_driver->ttm_mm;
+ static int check_aged = 0;
memset(emitted, 0, sizeof(int) * DRM_FENCE_TYPES);
spin_lock(&mm->mm.mm_lock);
@@ -1136,9 +1186,15 @@ void drm_ttm_fence_regions(drm_device_t * dev)
}
spin_unlock(&mm->mm.mm_lock);
+
+ if (!(check_aged++ & 0x0F) && drm_ttm_evict_aged(mm)) {
+ dev->mm_driver->mm_sarea->evict_tt_seq =
+ dev->mm_driver->mm_sarea->validation_seq + 1;
+ }
}
EXPORT_SYMBOL(drm_ttm_fence_regions);
+
/*
* Evict the first (oldest) region on the lru list, after its fence
* is fulfilled. Will fail if the lru list is empty (nothing to evict),
@@ -1184,7 +1240,6 @@ static int drm_ttm_evict_lru_sl(drm_ttm_backend_list_t * entry)
break;
spin_unlock(mm_lock);
- drm_ttm_destroy_delayed(entry->mm, TRUE);
up(&dev->struct_sem);
ret = drm_wait_buf_busy(evict_priv->region);
@@ -1198,7 +1253,6 @@ static int drm_ttm_evict_lru_sl(drm_ttm_backend_list_t * entry)
}
} while (TRUE);
-
evict_node = evict_priv->region->mm_node;
drm_evict_ttm_region(evict_priv->region);
list_del_init(list);
diff --git a/linux-core/i915_ttm.c b/linux-core/i915_ttm.c
index 607f3e92..6e698b50 100644
--- a/linux-core/i915_ttm.c
+++ b/linux-core/i915_ttm.c
@@ -18,7 +18,6 @@ static void i915_mm_takedown(drm_mm_driver_t *mm_driver)
drm_free(mm_driver, sizeof(*mm_driver), DRM_MEM_MM);
}
-
drm_mm_driver_t *i915_mm_init(drm_device_t * dev)
{
drm_mm_driver_t *mm_driver =
@@ -30,6 +29,7 @@ drm_mm_driver_t *i915_mm_init(drm_device_t * dev)
mm_driver->emit_fence = i915_emit_fence;
mm_driver->wait_fence = i915_wait_fence;
mm_driver->test_fence = i915_test_fence;
+ mm_driver->fence_aged = i915_fence_aged;
mm_driver->create_ttm_backend_entry = i915_create_ttm_backend_entry;
mm_driver->flush_caches = i915_emit_mi_flush;
mm_driver->cached_pages = TRUE;
diff --git a/shared-core/i915_drv.h b/shared-core/i915_drv.h
index d9bfd26c..29771c3a 100644
--- a/shared-core/i915_drv.h
+++ b/shared-core/i915_drv.h
@@ -124,6 +124,7 @@ extern void i915_driver_irq_uninstall(drm_device_t * dev);
extern uint32_t i915_emit_fence(drm_device_t * dev, uint32_t type);
extern int i915_wait_fence(drm_device_t * dev, uint32_t type, uint32_t fence);
extern int i915_test_fence(drm_device_t * dev, uint32_t type, uint32_t fence);
+extern int i915_fence_aged(drm_device_t * dev, uint32_t type, uint32_t fence);
/* i915_mem.c */
diff --git a/shared-core/i915_irq.c b/shared-core/i915_irq.c
index f31a4e53..72cdbeb0 100644
--- a/shared-core/i915_irq.c
+++ b/shared-core/i915_irq.c
@@ -268,6 +268,21 @@ int i915_test_fence(drm_device_t *dev, uint32_t type, uint32_t fence)
return tmp;
}
+int i915_fence_aged(drm_device_t *dev, uint32_t type, uint32_t fence)
+{
+ drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
+ uint32_t tmp;
+
+ if (!dev_priv) {
+ DRM_ERROR("called without initialization\n");
+ return TRUE;
+ }
+
+ tmp = READ_BREADCRUMB(dev_priv);
+ return ((tmp - fence) > DRM_MM_CLEAN);
+}
+
+
int i915_wait_fence(drm_device_t * dev, uint32_t type, uint32_t fence)
{