From d799a4be27a30c8d7171a7b896ba229432c08698 Mon Sep 17 00:00:00 2001 From: Lucas Stach Date: Fri, 10 Dec 2021 22:46:37 +0100 Subject: [PATCH] etnaviv: drm: defer destruction of softpin BOs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When destroying a BO with a userspace managed address and thus freeing the VMA space, we need to make sure that the BO isn't in use by any active submit anymore, as the kernel will rightfully reject the next submit that re-uses the still active VMA. Keep the BO alive as long as it isn't fully idle to prevent the VMA being reused prematurely. Signed-off-by: Lucas Stach Tested-by: Guido Günther Reviewed-by: Christian Gmeiner Part-of: --- src/etnaviv/drm/etnaviv_bo.c | 47 +++++++++++++++++++++++++++++++- src/etnaviv/drm/etnaviv_device.c | 5 +++- src/etnaviv/drm/etnaviv_priv.h | 2 ++ 3 files changed, 52 insertions(+), 2 deletions(-) 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);