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