146686Sbrian/*-
246686Sbrian * Copyright (c) 2011 The FreeBSD Foundation
346686Sbrian * All rights reserved.
446686Sbrian *
546686Sbrian * This software was developed by Konstantin Belousov under sponsorship from
646686Sbrian * the FreeBSD Foundation.
746686Sbrian *
846686Sbrian * Redistribution and use in source and binary forms, with or without
946686Sbrian * modification, are permitted provided that the following conditions
1046686Sbrian * are met:
1146686Sbrian * 1. Redistributions of source code must retain the above copyright
1246686Sbrian *    notice, this list of conditions and the following disclaimer.
1346686Sbrian * 2. Redistributions in binary form must reproduce the above copyright
1446686Sbrian *    notice, this list of conditions and the following disclaimer in the
1546686Sbrian *    documentation and/or other materials provided with the distribution.
1646686Sbrian *
1746686Sbrian * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1846686Sbrian * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1946686Sbrian * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2046686Sbrian * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
2146686Sbrian * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2246686Sbrian * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2346686Sbrian * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2446686Sbrian * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2546686Sbrian * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2650479Speter * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2746686Sbrian * SUCH DAMAGE.
2846686Sbrian */
2946686Sbrian
3046686Sbrian#include <sys/cdefs.h>
3146686Sbrian__FBSDID("$FreeBSD: releng/10.3/sys/dev/drm2/drm_gem_names.c 282199 2015-04-28 19:35:05Z dumbbell $");
3246686Sbrian
3346686Sbrian#include <sys/param.h>
3446686Sbrian#include <sys/systm.h>
3546686Sbrian#include <sys/kernel.h>
3646686Sbrian#include <sys/limits.h>
3746686Sbrian#include <sys/malloc.h>
3846686Sbrian
3947769Sbrian#include <dev/drm2/drm_gem_names.h>
4046686Sbrian
4146686SbrianMALLOC_DEFINE(M_GEM_NAMES, "gem_name", "Hash headers for the gem names");
4246686Sbrian
4346686Sbrianstatic void drm_gem_names_delete_name(struct drm_gem_names *names,
4446686Sbrian    struct drm_gem_name *np);
4546686Sbrian
4646686Sbrianvoid
4746686Sbriandrm_gem_names_init(struct drm_gem_names *names)
4846686Sbrian{
4946686Sbrian
5046686Sbrian	names->unr = new_unrhdr(1, INT_MAX, NULL); /* XXXKIB */
5146686Sbrian	names->names_hash = hashinit(1000 /* XXXKIB */, M_GEM_NAMES,
5246686Sbrian	    &names->hash_mask);
5346686Sbrian	mtx_init(&names->lock, "drmnames", NULL, MTX_DEF);
5446686Sbrian}
5546686Sbrian
5646686Sbrianvoid
5746686Sbriandrm_gem_names_fini(struct drm_gem_names *names)
5846686Sbrian{
5946686Sbrian	struct drm_gem_name *np;
6046686Sbrian	int i;
6146686Sbrian
6246686Sbrian	mtx_lock(&names->lock);
6346686Sbrian	for (i = 0; i <= names->hash_mask; i++) {
6446686Sbrian		while ((np = LIST_FIRST(&names->names_hash[i])) != NULL) {
6555253Sbrian			drm_gem_names_delete_name(names, np);
6646686Sbrian			mtx_lock(&names->lock);
6746686Sbrian		}
6847061Sbrian	}
6947061Sbrian	mtx_unlock(&names->lock);
7047061Sbrian	mtx_destroy(&names->lock);
7178410Sbrian	hashdestroy(names->names_hash, M_GEM_NAMES, names->hash_mask);
7253733Sbrian	delete_unrhdr(names->unr);
7347061Sbrian}
7447061Sbrian
7547061Sbrianstatic struct drm_gem_names_head *
7647061Sbriangem_name_hash_index(struct drm_gem_names *names, int name)
7747061Sbrian{
7847061Sbrian
7947061Sbrian	return (&names->names_hash[name & names->hash_mask]);
8047061Sbrian}
8147061Sbrian
8249472Sbrianvoid *
8352942Sbriandrm_gem_name_ref(struct drm_gem_names *names, uint32_t name,
8447061Sbrian    void (*ref)(void *))
8547061Sbrian{
8647061Sbrian	struct drm_gem_name *n;
8747061Sbrian
8847061Sbrian	mtx_lock(&names->lock);
8952942Sbrian	LIST_FOREACH(n, gem_name_hash_index(names, name), link) {
9046686Sbrian		if (n->name == name) {
9147461Sbrian			if (ref != NULL)
9247769Sbrian				ref(n->ptr);
9361973Sbrian			mtx_unlock(&names->lock);
9447061Sbrian			return (n->ptr);
9547461Sbrian		}
9647061Sbrian	}
9747061Sbrian	mtx_unlock(&names->lock);
9847061Sbrian	return (NULL);
9947061Sbrian}
10047061Sbrian
10147061Sbrianstruct drm_gem_ptr_match_arg {
10247061Sbrian	uint32_t res;
10347061Sbrian	void *ptr;
10460864Sbrian};
10546686Sbrian
10652942Sbrianstatic int
10760864Sbriandrm_gem_ptr_match(uint32_t name, void *ptr, void *arg)
10852942Sbrian{
10960864Sbrian	struct drm_gem_ptr_match_arg *a;
11046686Sbrian
11160864Sbrian	a = arg;
11246686Sbrian	if (ptr == a->ptr) {
11360946Sbrian		a->res = name;
11460864Sbrian		return (1);
11547849Sbrian	} else
11646686Sbrian		return (0);
11746686Sbrian}
11846686Sbrian
11946686Sbrianuint32_t
12046686Sbriandrm_gem_find_name(struct drm_gem_names *names, void *ptr)
12146686Sbrian{
12246686Sbrian	struct drm_gem_ptr_match_arg arg;
12347849Sbrian
12460864Sbrian	arg.res = 0;
12560864Sbrian	arg.ptr = ptr;
12660864Sbrian	drm_gem_names_foreach(names, drm_gem_ptr_match, &arg);
12760864Sbrian	return (arg.res);
12860864Sbrian}
12946686Sbrian
13060864Sbrianvoid *
13160864Sbriandrm_gem_find_ptr(struct drm_gem_names *names, uint32_t name)
13260864Sbrian{
13360864Sbrian	struct drm_gem_name *n;
13458454Sbrian	void *res;
13546686Sbrian
13646686Sbrian	mtx_lock(&names->lock);
13746686Sbrian	LIST_FOREACH(n, gem_name_hash_index(names, name), link) {
13860864Sbrian		if (n->name == name) {
13946686Sbrian			res = n->ptr;
14046686Sbrian			mtx_unlock(&names->lock);
14164802Sbrian			return (res);
14255252Sbrian		}
14364802Sbrian	}
14446686Sbrian	mtx_unlock(&names->lock);
14558454Sbrian	return (NULL);
14660864Sbrian}
14746686Sbrian
14860864Sbrianint
14946686Sbriandrm_gem_name_create(struct drm_gem_names *names, void *p, uint32_t *name)
15046686Sbrian{
15146686Sbrian	struct drm_gem_name *np;
15258454Sbrian
15360864Sbrian	if (*name != 0) {
15460864Sbrian		return (-EALREADY);
15560864Sbrian	}
15658454Sbrian
15758454Sbrian	np = malloc(sizeof(struct drm_gem_name), M_GEM_NAMES, M_WAITOK);
15846686Sbrian	mtx_lock(&names->lock);
15960864Sbrian	np->name = alloc_unr(names->unr);
16060864Sbrian	if (np->name == -1) {
16158454Sbrian		mtx_unlock(&names->lock);
16246686Sbrian		free(np, M_GEM_NAMES);
16346686Sbrian		return (-ENOMEM);
16449976Sbrian	}
16549976Sbrian	*name = np->name;
16655145Sbrian	np->ptr = p;
16755145Sbrian	LIST_INSERT_HEAD(gem_name_hash_index(names, np->name), np, link);
16854914Sbrian	mtx_unlock(&names->lock);
16958454Sbrian	return (0);
17054914Sbrian}
17154914Sbrian
17254914Sbrianstatic void
17354914Sbriandrm_gem_names_delete_name(struct drm_gem_names *names, struct drm_gem_name *np)
17454914Sbrian{
17546686Sbrian
17646686Sbrian	mtx_assert(&names->lock, MA_OWNED);
17746686Sbrian	LIST_REMOVE(np, link);
17849976Sbrian	mtx_unlock(&names->lock);
17949976Sbrian	free_unr(names->unr, np->name);
18046686Sbrian	free(np, M_GEM_NAMES);
18146686Sbrian}
18258454Sbrian
18358454Sbrianvoid *
18458454Sbriandrm_gem_names_remove(struct drm_gem_names *names, uint32_t name)
18546686Sbrian{
18646686Sbrian	struct drm_gem_name *n;
18746686Sbrian	void *res;
18860864Sbrian
18946686Sbrian	mtx_lock(&names->lock);
19060864Sbrian	LIST_FOREACH(n, gem_name_hash_index(names, name), link) {
19160864Sbrian		if (n->name == name) {
19260864Sbrian			res = n->ptr;
19360864Sbrian			drm_gem_names_delete_name(names, n);
19458454Sbrian			return (res);
19558454Sbrian		}
19658454Sbrian	}
19758454Sbrian	mtx_unlock(&names->lock);
19858454Sbrian	return (NULL);
19958454Sbrian}
20060864Sbrian
20158454Sbrianvoid
20258454Sbriandrm_gem_names_foreach(struct drm_gem_names *names,
20358454Sbrian    int (*f)(uint32_t, void *, void *), void *arg)
20458454Sbrian{
20558454Sbrian	struct drm_gem_name *np;
20660864Sbrian	struct drm_gem_name marker;
20758454Sbrian	int i, fres;
20858454Sbrian
20958454Sbrian	bzero(&marker, sizeof(marker));
21058454Sbrian	marker.name = -1;
21158454Sbrian	mtx_lock(&names->lock);
21258454Sbrian	for (i = 0; i <= names->hash_mask; i++) {
21358454Sbrian		for (np = LIST_FIRST(&names->names_hash[i]); np != NULL; ) {
21458454Sbrian			if (np->name == -1) {
21558454Sbrian				np = LIST_NEXT(np, link);
21660864Sbrian				continue;
21758454Sbrian			}
21858454Sbrian			LIST_INSERT_AFTER(np, &marker, link);
21946686Sbrian			mtx_unlock(&names->lock);
22058038Sbrian			fres = f(np->name, np->ptr, arg);
22160864Sbrian			mtx_lock(&names->lock);
22253733Sbrian			np = LIST_NEXT(&marker, link);
22353733Sbrian			LIST_REMOVE(&marker, link);
22447061Sbrian			if (fres)
22546686Sbrian				break;
22658454Sbrian		}
22746686Sbrian	}
22846686Sbrian	mtx_unlock(&names->lock);
22946686Sbrian}
23047061Sbrian