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