static struct vc4_bo * vc4_bo_from_cache(struct vc4_screen *screen, uint32_t size, const char *name) { struct vc4_bo_cache *cache = &screen->bo_cache; uint32_t page_index = size / 4096 - 1; if (cache->size_list_size <= page_index) return NULL; struct vc4_bo *bo = NULL; mtx_lock(&cache->lock); if (!list_empty(&cache->size_list[page_index])) { bo = LIST_ENTRY(struct vc4_bo, cache->size_list[page_index].next, size_list); /* Check that the BO has gone idle. If not, then we want to * allocate something new instead, since we assume that the * user will proceed to CPU map it and fill it with stuff. */ if (!vc4_bo_wait(bo, 0, NULL)) { mtx_unlock(&cache->lock); return NULL; } pipe_reference_init(&bo->reference, 1); vc4_bo_remove_from_cache(cache, bo); bo->name = name; }
static struct vc4_bo *vc4_bo_get_from_cache(struct drm_device *dev, uint32_t size) { struct vc4_dev *vc4 = to_vc4_dev(dev); uint32_t page_index = bo_page_index(size); struct vc4_bo *bo = NULL; size = roundup(size, PAGE_SIZE); mutex_lock(&vc4->bo_lock); if (page_index >= vc4->bo_cache.size_list_size) goto out; if (list_empty(&vc4->bo_cache.size_list[page_index])) goto out; bo = list_first_entry(&vc4->bo_cache.size_list[page_index], struct vc4_bo, size_head); vc4_bo_remove_from_cache(bo); kref_init(&bo->base.base.refcount); out: mutex_unlock(&vc4->bo_lock); return bo; }
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); } }