From b5e6a6ef50c14eb81b6b1a2a93729fa286fdea8e Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Wed, 29 Mar 2006 13:17:32 +0000 Subject: ttm/intel: Add means for fence ageing and eviction of old regions. libdrm: Be paranoid and always validate buffers when told to do so. --- libdrm/xf86mm.c | 20 +++++++--------- linux-core/drmP.h | 2 ++ linux-core/drm_ttm.c | 64 ++++++++++++++++++++++++++++++++++++++++++++++---- linux-core/i915_ttm.c | 2 +- shared-core/i915_drv.h | 1 + shared-core/i915_irq.c | 15 ++++++++++++ 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) { -- cgit v1.2.3