diff --git a/src/etnaviv/drm/etnaviv_bo.c b/src/etnaviv/drm/etnaviv_bo.c index 64d049b345a..fc91990cf28 100644 --- a/src/etnaviv/drm/etnaviv_bo.c +++ b/src/etnaviv/drm/etnaviv_bo.c @@ -51,7 +51,7 @@ int etna_bo_is_idle(struct etna_bo *bo) } /* Called under etna_drm_table_lock */ -void etna_bo_free(struct etna_bo *bo) +static void _etna_bo_free(struct etna_bo *bo) { DEBUG_BO("Del bo:", bo); VG_BO_FREE(bo); @@ -79,6 +79,51 @@ void etna_bo_free(struct etna_bo *bo) free(bo); } +void etna_bo_kill_zombies(struct etna_device *dev) +{ + simple_mtx_assert_locked(&etna_drm_table_lock); + + list_for_each_entry_safe(struct etna_bo, bo, &dev->zombie_list, list) { + VG_BO_OBTAIN(bo); + list_del(&bo->list); + _etna_bo_free(bo); + } +} + + +static void etna_bo_cleanup_zombies(struct etna_device *dev) +{ + simple_mtx_assert_locked(&etna_drm_table_lock); + + list_for_each_entry_safe(struct etna_bo, bo, &dev->zombie_list, list) { + /* Stop once we reach a busy BO - all others past this point were + * freed more recently so are likely also busy. + */ + if (!etna_bo_is_idle(bo)) + break; + + VG_BO_OBTAIN(bo); + list_del(&bo->list); + _etna_bo_free(bo); + } +} + +void etna_bo_free(struct etna_bo *bo) { + struct etna_device *dev = bo->dev; + + /* If the BO has a userspace managed address we don't free it immediately, + * but keep it on a deferred destroy list until all submits with the buffer + * have finished, at which point we can reuse the VMA space. + */ + if (dev->use_softpin) { + etna_bo_cleanup_zombies(dev); + VG_BO_RELEASE(bo); + list_addtail(&bo->list, &dev->zombie_list); + } else { + _etna_bo_free(bo); + } +} + /* lookup a buffer from it's handle, call w/ etna_drm_table_lock held: */ static struct etna_bo *lookup_bo(void *tbl, uint32_t handle) { diff --git a/src/etnaviv/drm/etnaviv_device.c b/src/etnaviv/drm/etnaviv_device.c index 7c1aa90ff3a..c2b90714338 100644 --- a/src/etnaviv/drm/etnaviv_device.c +++ b/src/etnaviv/drm/etnaviv_device.c @@ -72,6 +72,7 @@ out: if (!ret && req.value != ~0ULL) { const uint64_t _4GB = 1ull << 32; + list_inithead(&dev->zombie_list); util_vma_heap_init(&dev->address_space, req.value, _4GB - req.value); dev->use_softpin = 1; } @@ -105,8 +106,10 @@ static void etna_device_del_impl(struct etna_device *dev) { etna_bo_cache_cleanup(&dev->bo_cache, 0); - if (dev->use_softpin) + if (dev->use_softpin) { + etna_bo_kill_zombies(dev); util_vma_heap_finish(&dev->address_space); + } _mesa_hash_table_destroy(dev->handle_table, NULL); _mesa_hash_table_destroy(dev->name_table, NULL); diff --git a/src/etnaviv/drm/etnaviv_priv.h b/src/etnaviv/drm/etnaviv_priv.h index 3e8d673447d..f6be72357cb 100644 --- a/src/etnaviv/drm/etnaviv_priv.h +++ b/src/etnaviv/drm/etnaviv_priv.h @@ -81,6 +81,7 @@ struct etna_device { void *handle_table, *name_table; struct etna_bo_cache bo_cache; + struct list_head zombie_list; int use_softpin; struct util_vma_heap address_space; @@ -89,6 +90,7 @@ struct etna_device { }; void etna_bo_free(struct etna_bo *bo); +void etna_bo_kill_zombies(struct etna_device *dev); void etna_bo_cache_init(struct etna_bo_cache *cache); void etna_bo_cache_cleanup(struct etna_bo_cache *cache, time_t time);