1251875Speter/*- 2251875Speter * SPDX-License-Identifier: BSD-2-Clause 3251875Speter * 4251875Speter * Copyright (c) 2011 The FreeBSD Foundation 5251875Speter * 6251875Speter * This software was developed by Konstantin Belousov under sponsorship from 7251875Speter * the FreeBSD Foundation. 8251875Speter * 9251875Speter * Redistribution and use in source and binary forms, with or without 10251875Speter * modification, are permitted provided that the following conditions 11251875Speter * are met: 12251875Speter * 1. Redistributions of source code must retain the above copyright 13251875Speter * notice, this list of conditions and the following disclaimer. 14251875Speter * 2. Redistributions in binary form must reproduce the above copyright 15251875Speter * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28 * SUCH DAMAGE. 29 */ 30 31#include <sys/param.h> 32#include <sys/systm.h> 33#include <sys/kernel.h> 34#include <sys/limits.h> 35#include <sys/malloc.h> 36 37#include <dev/drm2/drm_gem_names.h> 38 39MALLOC_DEFINE(M_GEM_NAMES, "gem_name", "Hash headers for the gem names"); 40 41static void drm_gem_names_delete_name(struct drm_gem_names *names, 42 struct drm_gem_name *np); 43 44void 45drm_gem_names_init(struct drm_gem_names *names) 46{ 47 48 names->unr = new_unrhdr(1, INT_MAX, NULL); /* XXXKIB */ 49 names->names_hash = hashinit(1000 /* XXXKIB */, M_GEM_NAMES, 50 &names->hash_mask); 51 mtx_init(&names->lock, "drmnames", NULL, MTX_DEF); 52} 53 54void 55drm_gem_names_fini(struct drm_gem_names *names) 56{ 57 struct drm_gem_name *np; 58 int i; 59 60 mtx_lock(&names->lock); 61 for (i = 0; i <= names->hash_mask; i++) { 62 while ((np = LIST_FIRST(&names->names_hash[i])) != NULL) { 63 drm_gem_names_delete_name(names, np); 64 mtx_lock(&names->lock); 65 } 66 } 67 mtx_unlock(&names->lock); 68 mtx_destroy(&names->lock); 69 hashdestroy(names->names_hash, M_GEM_NAMES, names->hash_mask); 70 delete_unrhdr(names->unr); 71} 72 73static struct drm_gem_names_head * 74gem_name_hash_index(struct drm_gem_names *names, int name) 75{ 76 77 return (&names->names_hash[name & names->hash_mask]); 78} 79 80void * 81drm_gem_name_ref(struct drm_gem_names *names, uint32_t name, 82 void (*ref)(void *)) 83{ 84 struct drm_gem_name *n; 85 86 mtx_lock(&names->lock); 87 LIST_FOREACH(n, gem_name_hash_index(names, name), link) { 88 if (n->name == name) { 89 if (ref != NULL) 90 ref(n->ptr); 91 mtx_unlock(&names->lock); 92 return (n->ptr); 93 } 94 } 95 mtx_unlock(&names->lock); 96 return (NULL); 97} 98 99struct drm_gem_ptr_match_arg { 100 uint32_t res; 101 void *ptr; 102}; 103 104static int 105drm_gem_ptr_match(uint32_t name, void *ptr, void *arg) 106{ 107 struct drm_gem_ptr_match_arg *a; 108 109 a = arg; 110 if (ptr == a->ptr) { 111 a->res = name; 112 return (1); 113 } else 114 return (0); 115} 116 117uint32_t 118drm_gem_find_name(struct drm_gem_names *names, void *ptr) 119{ 120 struct drm_gem_ptr_match_arg arg; 121 122 arg.res = 0; 123 arg.ptr = ptr; 124 drm_gem_names_foreach(names, drm_gem_ptr_match, &arg); 125 return (arg.res); 126} 127 128void * 129drm_gem_find_ptr(struct drm_gem_names *names, uint32_t name) 130{ 131 struct drm_gem_name *n; 132 void *res; 133 134 mtx_lock(&names->lock); 135 LIST_FOREACH(n, gem_name_hash_index(names, name), link) { 136 if (n->name == name) { 137 res = n->ptr; 138 mtx_unlock(&names->lock); 139 return (res); 140 } 141 } 142 mtx_unlock(&names->lock); 143 return (NULL); 144} 145 146int 147drm_gem_name_create(struct drm_gem_names *names, void *p, uint32_t *name) 148{ 149 struct drm_gem_name *np; 150 151 if (*name != 0) { 152 return (-EALREADY); 153 } 154 155 np = malloc(sizeof(struct drm_gem_name), M_GEM_NAMES, M_WAITOK); 156 mtx_lock(&names->lock); 157 np->name = alloc_unr(names->unr); 158 if (np->name == -1) { 159 mtx_unlock(&names->lock); 160 free(np, M_GEM_NAMES); 161 return (-ENOMEM); 162 } 163 *name = np->name; 164 np->ptr = p; 165 LIST_INSERT_HEAD(gem_name_hash_index(names, np->name), np, link); 166 mtx_unlock(&names->lock); 167 return (0); 168} 169 170static void 171drm_gem_names_delete_name(struct drm_gem_names *names, struct drm_gem_name *np) 172{ 173 174 mtx_assert(&names->lock, MA_OWNED); 175 LIST_REMOVE(np, link); 176 mtx_unlock(&names->lock); 177 free_unr(names->unr, np->name); 178 free(np, M_GEM_NAMES); 179} 180 181void * 182drm_gem_names_remove(struct drm_gem_names *names, uint32_t name) 183{ 184 struct drm_gem_name *n; 185 void *res; 186 187 mtx_lock(&names->lock); 188 LIST_FOREACH(n, gem_name_hash_index(names, name), link) { 189 if (n->name == name) { 190 res = n->ptr; 191 drm_gem_names_delete_name(names, n); 192 return (res); 193 } 194 } 195 mtx_unlock(&names->lock); 196 return (NULL); 197} 198 199void 200drm_gem_names_foreach(struct drm_gem_names *names, 201 int (*f)(uint32_t, void *, void *), void *arg) 202{ 203 struct drm_gem_name *np; 204 struct drm_gem_name marker; 205 int i, fres; 206 207 bzero(&marker, sizeof(marker)); 208 marker.name = -1; 209 mtx_lock(&names->lock); 210 for (i = 0; i <= names->hash_mask; i++) { 211 for (np = LIST_FIRST(&names->names_hash[i]); np != NULL; ) { 212 if (np->name == -1) { 213 np = LIST_NEXT(np, link); 214 continue; 215 } 216 LIST_INSERT_AFTER(np, &marker, link); 217 mtx_unlock(&names->lock); 218 fres = f(np->name, np->ptr, arg); 219 mtx_lock(&names->lock); 220 np = LIST_NEXT(&marker, link); 221 LIST_REMOVE(&marker, link); 222 if (fres) 223 break; 224 } 225 } 226 mtx_unlock(&names->lock); 227} 228