195e2cc6a801d92a0634b75fb02221213bd11e9daThe etnaviv authors/* 295e2cc6a801d92a0634b75fb02221213bd11e9daThe etnaviv authors * Copyright (C) 2016 Etnaviv Project 395e2cc6a801d92a0634b75fb02221213bd11e9daThe etnaviv authors * 495e2cc6a801d92a0634b75fb02221213bd11e9daThe etnaviv authors * Permission is hereby granted, free of charge, to any person obtaining a 595e2cc6a801d92a0634b75fb02221213bd11e9daThe etnaviv authors * copy of this software and associated documentation files (the "Software"), 695e2cc6a801d92a0634b75fb02221213bd11e9daThe etnaviv authors * to deal in the Software without restriction, including without limitation 795e2cc6a801d92a0634b75fb02221213bd11e9daThe etnaviv authors * the rights to use, copy, modify, merge, publish, distribute, sublicense, 895e2cc6a801d92a0634b75fb02221213bd11e9daThe etnaviv authors * and/or sell copies of the Software, and to permit persons to whom the 995e2cc6a801d92a0634b75fb02221213bd11e9daThe etnaviv authors * Software is furnished to do so, subject to the following conditions: 1095e2cc6a801d92a0634b75fb02221213bd11e9daThe etnaviv authors * 1195e2cc6a801d92a0634b75fb02221213bd11e9daThe etnaviv authors * The above copyright notice and this permission notice (including the next 1295e2cc6a801d92a0634b75fb02221213bd11e9daThe etnaviv authors * paragraph) shall be included in all copies or substantial portions of the 1395e2cc6a801d92a0634b75fb02221213bd11e9daThe etnaviv authors * Software. 1495e2cc6a801d92a0634b75fb02221213bd11e9daThe etnaviv authors * 1595e2cc6a801d92a0634b75fb02221213bd11e9daThe etnaviv authors * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 1695e2cc6a801d92a0634b75fb02221213bd11e9daThe etnaviv authors * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 1795e2cc6a801d92a0634b75fb02221213bd11e9daThe etnaviv authors * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 1895e2cc6a801d92a0634b75fb02221213bd11e9daThe etnaviv authors * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 1995e2cc6a801d92a0634b75fb02221213bd11e9daThe etnaviv authors * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 2095e2cc6a801d92a0634b75fb02221213bd11e9daThe etnaviv authors * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 2195e2cc6a801d92a0634b75fb02221213bd11e9daThe etnaviv authors * SOFTWARE. 2295e2cc6a801d92a0634b75fb02221213bd11e9daThe etnaviv authors * 2395e2cc6a801d92a0634b75fb02221213bd11e9daThe etnaviv authors * Authors: 2495e2cc6a801d92a0634b75fb02221213bd11e9daThe etnaviv authors * Christian Gmeiner <christian.gmeiner@gmail.com> 2595e2cc6a801d92a0634b75fb02221213bd11e9daThe etnaviv authors */ 2695e2cc6a801d92a0634b75fb02221213bd11e9daThe etnaviv authors 2795e2cc6a801d92a0634b75fb02221213bd11e9daThe etnaviv authors#ifdef HAVE_CONFIG_H 2895e2cc6a801d92a0634b75fb02221213bd11e9daThe etnaviv authors# include <config.h> 2995e2cc6a801d92a0634b75fb02221213bd11e9daThe etnaviv authors#endif 3095e2cc6a801d92a0634b75fb02221213bd11e9daThe etnaviv authors 3195e2cc6a801d92a0634b75fb02221213bd11e9daThe etnaviv authors#include "etnaviv_priv.h" 3295e2cc6a801d92a0634b75fb02221213bd11e9daThe etnaviv authors#include "etnaviv_drmif.h" 3395e2cc6a801d92a0634b75fb02221213bd11e9daThe etnaviv authors 3495e2cc6a801d92a0634b75fb02221213bd11e9daThe etnaviv authorsdrm_private void bo_del(struct etna_bo *bo); 3595e2cc6a801d92a0634b75fb02221213bd11e9daThe etnaviv authorsdrm_private extern pthread_mutex_t table_lock; 3695e2cc6a801d92a0634b75fb02221213bd11e9daThe etnaviv authors 3795e2cc6a801d92a0634b75fb02221213bd11e9daThe etnaviv authorsstatic void add_bucket(struct etna_bo_cache *cache, int size) 3895e2cc6a801d92a0634b75fb02221213bd11e9daThe etnaviv authors{ 3995e2cc6a801d92a0634b75fb02221213bd11e9daThe etnaviv authors unsigned i = cache->num_buckets; 4095e2cc6a801d92a0634b75fb02221213bd11e9daThe etnaviv authors 4195e2cc6a801d92a0634b75fb02221213bd11e9daThe etnaviv authors assert(i < ARRAY_SIZE(cache->cache_bucket)); 4295e2cc6a801d92a0634b75fb02221213bd11e9daThe etnaviv authors 4395e2cc6a801d92a0634b75fb02221213bd11e9daThe etnaviv authors list_inithead(&cache->cache_bucket[i].list); 4495e2cc6a801d92a0634b75fb02221213bd11e9daThe etnaviv authors cache->cache_bucket[i].size = size; 4595e2cc6a801d92a0634b75fb02221213bd11e9daThe etnaviv authors cache->num_buckets++; 4695e2cc6a801d92a0634b75fb02221213bd11e9daThe etnaviv authors} 4795e2cc6a801d92a0634b75fb02221213bd11e9daThe etnaviv authors 4895e2cc6a801d92a0634b75fb02221213bd11e9daThe etnaviv authorsdrm_private void etna_bo_cache_init(struct etna_bo_cache *cache) 4995e2cc6a801d92a0634b75fb02221213bd11e9daThe etnaviv authors{ 5095e2cc6a801d92a0634b75fb02221213bd11e9daThe etnaviv authors unsigned long size, cache_max_size = 64 * 1024 * 1024; 5195e2cc6a801d92a0634b75fb02221213bd11e9daThe etnaviv authors 5295e2cc6a801d92a0634b75fb02221213bd11e9daThe etnaviv authors /* OK, so power of two buckets was too wasteful of memory. 5395e2cc6a801d92a0634b75fb02221213bd11e9daThe etnaviv authors * Give 3 other sizes between each power of two, to hopefully 5495e2cc6a801d92a0634b75fb02221213bd11e9daThe etnaviv authors * cover things accurately enough. (The alternative is 5595e2cc6a801d92a0634b75fb02221213bd11e9daThe etnaviv authors * probably to just go for exact matching of sizes, and assume 5695e2cc6a801d92a0634b75fb02221213bd11e9daThe etnaviv authors * that for things like composited window resize the tiled 5795e2cc6a801d92a0634b75fb02221213bd11e9daThe etnaviv authors * width/height alignment and rounding of sizes to pages will 5895e2cc6a801d92a0634b75fb02221213bd11e9daThe etnaviv authors * get us useful cache hit rates anyway) 5995e2cc6a801d92a0634b75fb02221213bd11e9daThe etnaviv authors */ 6095e2cc6a801d92a0634b75fb02221213bd11e9daThe etnaviv authors add_bucket(cache, 4096); 6195e2cc6a801d92a0634b75fb02221213bd11e9daThe etnaviv authors add_bucket(cache, 4096 * 2); 6295e2cc6a801d92a0634b75fb02221213bd11e9daThe etnaviv authors add_bucket(cache, 4096 * 3); 6395e2cc6a801d92a0634b75fb02221213bd11e9daThe etnaviv authors 6495e2cc6a801d92a0634b75fb02221213bd11e9daThe etnaviv authors /* Initialize the linked lists for BO reuse cache. */ 6595e2cc6a801d92a0634b75fb02221213bd11e9daThe etnaviv authors for (size = 4 * 4096; size <= cache_max_size; size *= 2) { 6695e2cc6a801d92a0634b75fb02221213bd11e9daThe etnaviv authors add_bucket(cache, size); 6795e2cc6a801d92a0634b75fb02221213bd11e9daThe etnaviv authors add_bucket(cache, size + size * 1 / 4); 6895e2cc6a801d92a0634b75fb02221213bd11e9daThe etnaviv authors add_bucket(cache, size + size * 2 / 4); 6995e2cc6a801d92a0634b75fb02221213bd11e9daThe etnaviv authors add_bucket(cache, size + size * 3 / 4); 7095e2cc6a801d92a0634b75fb02221213bd11e9daThe etnaviv authors } 7195e2cc6a801d92a0634b75fb02221213bd11e9daThe etnaviv authors} 7295e2cc6a801d92a0634b75fb02221213bd11e9daThe etnaviv authors 7395e2cc6a801d92a0634b75fb02221213bd11e9daThe etnaviv authors/* Frees older cached buffers. Called under table_lock */ 7495e2cc6a801d92a0634b75fb02221213bd11e9daThe etnaviv authorsdrm_private void etna_bo_cache_cleanup(struct etna_bo_cache *cache, time_t time) 7595e2cc6a801d92a0634b75fb02221213bd11e9daThe etnaviv authors{ 7695e2cc6a801d92a0634b75fb02221213bd11e9daThe etnaviv authors unsigned i; 7795e2cc6a801d92a0634b75fb02221213bd11e9daThe etnaviv authors 7895e2cc6a801d92a0634b75fb02221213bd11e9daThe etnaviv authors if (cache->time == time) 7995e2cc6a801d92a0634b75fb02221213bd11e9daThe etnaviv authors return; 8095e2cc6a801d92a0634b75fb02221213bd11e9daThe etnaviv authors 8195e2cc6a801d92a0634b75fb02221213bd11e9daThe etnaviv authors for (i = 0; i < cache->num_buckets; i++) { 8295e2cc6a801d92a0634b75fb02221213bd11e9daThe etnaviv authors struct etna_bo_bucket *bucket = &cache->cache_bucket[i]; 8395e2cc6a801d92a0634b75fb02221213bd11e9daThe etnaviv authors struct etna_bo *bo; 8495e2cc6a801d92a0634b75fb02221213bd11e9daThe etnaviv authors 8595e2cc6a801d92a0634b75fb02221213bd11e9daThe etnaviv authors while (!LIST_IS_EMPTY(&bucket->list)) { 8695e2cc6a801d92a0634b75fb02221213bd11e9daThe etnaviv authors bo = LIST_ENTRY(struct etna_bo, bucket->list.next, list); 8795e2cc6a801d92a0634b75fb02221213bd11e9daThe etnaviv authors 8895e2cc6a801d92a0634b75fb02221213bd11e9daThe etnaviv authors /* keep things in cache for at least 1 second: */ 8995e2cc6a801d92a0634b75fb02221213bd11e9daThe etnaviv authors if (time && ((time - bo->free_time) <= 1)) 9095e2cc6a801d92a0634b75fb02221213bd11e9daThe etnaviv authors break; 9195e2cc6a801d92a0634b75fb02221213bd11e9daThe etnaviv authors 9295e2cc6a801d92a0634b75fb02221213bd11e9daThe etnaviv authors list_del(&bo->list); 9395e2cc6a801d92a0634b75fb02221213bd11e9daThe etnaviv authors bo_del(bo); 9495e2cc6a801d92a0634b75fb02221213bd11e9daThe etnaviv authors } 9595e2cc6a801d92a0634b75fb02221213bd11e9daThe etnaviv authors } 9695e2cc6a801d92a0634b75fb02221213bd11e9daThe etnaviv authors 9795e2cc6a801d92a0634b75fb02221213bd11e9daThe etnaviv authors cache->time = time; 9895e2cc6a801d92a0634b75fb02221213bd11e9daThe etnaviv authors} 9995e2cc6a801d92a0634b75fb02221213bd11e9daThe etnaviv authors 10095e2cc6a801d92a0634b75fb02221213bd11e9daThe etnaviv authorsstatic struct etna_bo_bucket *get_bucket(struct etna_bo_cache *cache, uint32_t size) 10195e2cc6a801d92a0634b75fb02221213bd11e9daThe etnaviv authors{ 10295e2cc6a801d92a0634b75fb02221213bd11e9daThe etnaviv authors unsigned i; 10395e2cc6a801d92a0634b75fb02221213bd11e9daThe etnaviv authors 10495e2cc6a801d92a0634b75fb02221213bd11e9daThe etnaviv authors /* hmm, this is what intel does, but I suppose we could calculate our 10595e2cc6a801d92a0634b75fb02221213bd11e9daThe etnaviv authors * way to the correct bucket size rather than looping.. 10695e2cc6a801d92a0634b75fb02221213bd11e9daThe etnaviv authors */ 10795e2cc6a801d92a0634b75fb02221213bd11e9daThe etnaviv authors for (i = 0; i < cache->num_buckets; i++) { 10895e2cc6a801d92a0634b75fb02221213bd11e9daThe etnaviv authors struct etna_bo_bucket *bucket = &cache->cache_bucket[i]; 10995e2cc6a801d92a0634b75fb02221213bd11e9daThe etnaviv authors if (bucket->size >= size) { 11095e2cc6a801d92a0634b75fb02221213bd11e9daThe etnaviv authors return bucket; 11195e2cc6a801d92a0634b75fb02221213bd11e9daThe etnaviv authors } 11295e2cc6a801d92a0634b75fb02221213bd11e9daThe etnaviv authors } 11395e2cc6a801d92a0634b75fb02221213bd11e9daThe etnaviv authors 11495e2cc6a801d92a0634b75fb02221213bd11e9daThe etnaviv authors return NULL; 11595e2cc6a801d92a0634b75fb02221213bd11e9daThe etnaviv authors} 11695e2cc6a801d92a0634b75fb02221213bd11e9daThe etnaviv authors 11795e2cc6a801d92a0634b75fb02221213bd11e9daThe etnaviv authorsstatic int is_idle(struct etna_bo *bo) 11895e2cc6a801d92a0634b75fb02221213bd11e9daThe etnaviv authors{ 11995e2cc6a801d92a0634b75fb02221213bd11e9daThe etnaviv authors return etna_bo_cpu_prep(bo, 12095e2cc6a801d92a0634b75fb02221213bd11e9daThe etnaviv authors DRM_ETNA_PREP_READ | 12195e2cc6a801d92a0634b75fb02221213bd11e9daThe etnaviv authors DRM_ETNA_PREP_WRITE | 12295e2cc6a801d92a0634b75fb02221213bd11e9daThe etnaviv authors DRM_ETNA_PREP_NOSYNC) == 0; 12395e2cc6a801d92a0634b75fb02221213bd11e9daThe etnaviv authors} 12495e2cc6a801d92a0634b75fb02221213bd11e9daThe etnaviv authors 12595e2cc6a801d92a0634b75fb02221213bd11e9daThe etnaviv authorsstatic struct etna_bo *find_in_bucket(struct etna_bo_bucket *bucket, uint32_t flags) 12695e2cc6a801d92a0634b75fb02221213bd11e9daThe etnaviv authors{ 12795e2cc6a801d92a0634b75fb02221213bd11e9daThe etnaviv authors struct etna_bo *bo = NULL; 12895e2cc6a801d92a0634b75fb02221213bd11e9daThe etnaviv authors 12995e2cc6a801d92a0634b75fb02221213bd11e9daThe etnaviv authors pthread_mutex_lock(&table_lock); 13095e2cc6a801d92a0634b75fb02221213bd11e9daThe etnaviv authors while (!LIST_IS_EMPTY(&bucket->list)) { 13195e2cc6a801d92a0634b75fb02221213bd11e9daThe etnaviv authors bo = LIST_ENTRY(struct etna_bo, bucket->list.next, list); 13295e2cc6a801d92a0634b75fb02221213bd11e9daThe etnaviv authors 13395e2cc6a801d92a0634b75fb02221213bd11e9daThe etnaviv authors if (bo->flags == flags && is_idle(bo)) { 13495e2cc6a801d92a0634b75fb02221213bd11e9daThe etnaviv authors list_del(&bo->list); 13595e2cc6a801d92a0634b75fb02221213bd11e9daThe etnaviv authors break; 13695e2cc6a801d92a0634b75fb02221213bd11e9daThe etnaviv authors } 13795e2cc6a801d92a0634b75fb02221213bd11e9daThe etnaviv authors 13895e2cc6a801d92a0634b75fb02221213bd11e9daThe etnaviv authors bo = NULL; 13995e2cc6a801d92a0634b75fb02221213bd11e9daThe etnaviv authors break; 14095e2cc6a801d92a0634b75fb02221213bd11e9daThe etnaviv authors } 14195e2cc6a801d92a0634b75fb02221213bd11e9daThe etnaviv authors pthread_mutex_unlock(&table_lock); 14295e2cc6a801d92a0634b75fb02221213bd11e9daThe etnaviv authors 14395e2cc6a801d92a0634b75fb02221213bd11e9daThe etnaviv authors return bo; 14495e2cc6a801d92a0634b75fb02221213bd11e9daThe etnaviv authors} 14595e2cc6a801d92a0634b75fb02221213bd11e9daThe etnaviv authors 14695e2cc6a801d92a0634b75fb02221213bd11e9daThe etnaviv authors/* allocate a new (un-tiled) buffer object 14795e2cc6a801d92a0634b75fb02221213bd11e9daThe etnaviv authors * 14895e2cc6a801d92a0634b75fb02221213bd11e9daThe etnaviv authors * NOTE: size is potentially rounded up to bucket size 14995e2cc6a801d92a0634b75fb02221213bd11e9daThe etnaviv authors */ 15095e2cc6a801d92a0634b75fb02221213bd11e9daThe etnaviv authorsdrm_private struct etna_bo *etna_bo_cache_alloc(struct etna_bo_cache *cache, uint32_t *size, 15195e2cc6a801d92a0634b75fb02221213bd11e9daThe etnaviv authors uint32_t flags) 15295e2cc6a801d92a0634b75fb02221213bd11e9daThe etnaviv authors{ 15395e2cc6a801d92a0634b75fb02221213bd11e9daThe etnaviv authors struct etna_bo *bo; 15495e2cc6a801d92a0634b75fb02221213bd11e9daThe etnaviv authors struct etna_bo_bucket *bucket; 15595e2cc6a801d92a0634b75fb02221213bd11e9daThe etnaviv authors 15695e2cc6a801d92a0634b75fb02221213bd11e9daThe etnaviv authors *size = ALIGN(*size, 4096); 15795e2cc6a801d92a0634b75fb02221213bd11e9daThe etnaviv authors bucket = get_bucket(cache, *size); 15895e2cc6a801d92a0634b75fb02221213bd11e9daThe etnaviv authors 15995e2cc6a801d92a0634b75fb02221213bd11e9daThe etnaviv authors /* see if we can be green and recycle: */ 16095e2cc6a801d92a0634b75fb02221213bd11e9daThe etnaviv authors if (bucket) { 16195e2cc6a801d92a0634b75fb02221213bd11e9daThe etnaviv authors *size = bucket->size; 16295e2cc6a801d92a0634b75fb02221213bd11e9daThe etnaviv authors bo = find_in_bucket(bucket, flags); 16395e2cc6a801d92a0634b75fb02221213bd11e9daThe etnaviv authors if (bo) { 16495e2cc6a801d92a0634b75fb02221213bd11e9daThe etnaviv authors atomic_set(&bo->refcnt, 1); 16595e2cc6a801d92a0634b75fb02221213bd11e9daThe etnaviv authors etna_device_ref(bo->dev); 16695e2cc6a801d92a0634b75fb02221213bd11e9daThe etnaviv authors return bo; 16795e2cc6a801d92a0634b75fb02221213bd11e9daThe etnaviv authors } 16895e2cc6a801d92a0634b75fb02221213bd11e9daThe etnaviv authors } 16995e2cc6a801d92a0634b75fb02221213bd11e9daThe etnaviv authors 17095e2cc6a801d92a0634b75fb02221213bd11e9daThe etnaviv authors return NULL; 17195e2cc6a801d92a0634b75fb02221213bd11e9daThe etnaviv authors} 17295e2cc6a801d92a0634b75fb02221213bd11e9daThe etnaviv authors 17395e2cc6a801d92a0634b75fb02221213bd11e9daThe etnaviv authorsdrm_private int etna_bo_cache_free(struct etna_bo_cache *cache, struct etna_bo *bo) 17495e2cc6a801d92a0634b75fb02221213bd11e9daThe etnaviv authors{ 17595e2cc6a801d92a0634b75fb02221213bd11e9daThe etnaviv authors struct etna_bo_bucket *bucket = get_bucket(cache, bo->size); 17695e2cc6a801d92a0634b75fb02221213bd11e9daThe etnaviv authors 17795e2cc6a801d92a0634b75fb02221213bd11e9daThe etnaviv authors /* see if we can be green and recycle: */ 17895e2cc6a801d92a0634b75fb02221213bd11e9daThe etnaviv authors if (bucket) { 17995e2cc6a801d92a0634b75fb02221213bd11e9daThe etnaviv authors struct timespec time; 18095e2cc6a801d92a0634b75fb02221213bd11e9daThe etnaviv authors 18195e2cc6a801d92a0634b75fb02221213bd11e9daThe etnaviv authors clock_gettime(CLOCK_MONOTONIC, &time); 18295e2cc6a801d92a0634b75fb02221213bd11e9daThe etnaviv authors 18395e2cc6a801d92a0634b75fb02221213bd11e9daThe etnaviv authors bo->free_time = time.tv_sec; 18495e2cc6a801d92a0634b75fb02221213bd11e9daThe etnaviv authors list_addtail(&bo->list, &bucket->list); 18595e2cc6a801d92a0634b75fb02221213bd11e9daThe etnaviv authors etna_bo_cache_cleanup(cache, time.tv_sec); 18695e2cc6a801d92a0634b75fb02221213bd11e9daThe etnaviv authors 18795e2cc6a801d92a0634b75fb02221213bd11e9daThe etnaviv authors /* bo's in the bucket cache don't have a ref and 18895e2cc6a801d92a0634b75fb02221213bd11e9daThe etnaviv authors * don't hold a ref to the dev: 18995e2cc6a801d92a0634b75fb02221213bd11e9daThe etnaviv authors */ 19095e2cc6a801d92a0634b75fb02221213bd11e9daThe etnaviv authors etna_device_del_locked(bo->dev); 19195e2cc6a801d92a0634b75fb02221213bd11e9daThe etnaviv authors 19295e2cc6a801d92a0634b75fb02221213bd11e9daThe etnaviv authors return 0; 19395e2cc6a801d92a0634b75fb02221213bd11e9daThe etnaviv authors } 19495e2cc6a801d92a0634b75fb02221213bd11e9daThe etnaviv authors 19595e2cc6a801d92a0634b75fb02221213bd11e9daThe etnaviv authors return -1; 19695e2cc6a801d92a0634b75fb02221213bd11e9daThe etnaviv authors} 197