/* Called on the last userspace/kernel unreference of the BO. Returns * it to the BO cache if possible, otherwise frees it. */ void vc4_free_object(struct drm_gem_object *gem_bo) { struct drm_device *dev = gem_bo->dev; struct vc4_dev *vc4 = to_vc4_dev(dev); struct vc4_bo *bo = to_vc4_bo(gem_bo); struct list_head *cache_list; mutex_lock(&vc4->bo_lock); /* If the object references someone else's memory, we can't cache it. */ if (gem_bo->import_attach) { vc4_bo_destroy(bo); goto out; } /* Don't cache if it was publicly named. */ if (gem_bo->name) { vc4_bo_destroy(bo); goto out; } /* If this object was partially constructed but CMA allocation * had failed, just free it. */ if (!bo->base.vaddr) { vc4_bo_destroy(bo); goto out; } cache_list = vc4_get_cache_list_for_size(dev, gem_bo->size); if (!cache_list) { vc4_bo_destroy(bo); goto out; } if (bo->validated_shader) { kfree(bo->validated_shader->texture_samples); kfree(bo->validated_shader); bo->validated_shader = NULL; } bo->free_time = jiffies; list_add(&bo->size_head, cache_list); list_add(&bo->unref_head, &vc4->bo_cache.time_list); vc4->bo_stats.num_cached++; vc4->bo_stats.size_cached += gem_bo->size; vc4_bo_cache_free_old(dev); out: mutex_unlock(&vc4->bo_lock); }
void vc4_bo_cache_purge(struct drm_device *dev) { struct vc4_dev *vc4 = to_vc4_dev(dev); mutex_lock(&vc4->bo_lock); while (!list_empty(&vc4->bo_cache.time_list)) { struct vc4_bo *bo = list_last_entry(&vc4->bo_cache.time_list, struct vc4_bo, unref_head); vc4_bo_remove_from_cache(bo); vc4_bo_destroy(bo); } mutex_unlock(&vc4->bo_lock); }
/* Must be called with bo_lock held. */ static void vc4_bo_cache_free_old(struct drm_device *dev) { struct vc4_dev *vc4 = to_vc4_dev(dev); unsigned long expire_time = jiffies - msecs_to_jiffies(1000); while (!list_empty(&vc4->bo_cache.time_list)) { struct vc4_bo *bo = list_last_entry(&vc4->bo_cache.time_list, struct vc4_bo, unref_head); if (time_before(expire_time, bo->free_time)) { mod_timer(&vc4->bo_cache.time_timer, round_jiffies_up(jiffies + msecs_to_jiffies(1000))); return; } vc4_bo_remove_from_cache(bo); vc4_bo_destroy(bo); } }