1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause 3 * 4 * Copyright (c) 2011 The FreeBSD Foundation 5 * 6 * This software was developed by Konstantin Belousov under sponsorship from 7 * the FreeBSD Foundation. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * 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/cdefs.h> 32 __FBSDID("$FreeBSD$"); 33 34 #include <sys/param.h> 35 #include <sys/systm.h> 36 #include <sys/kernel.h> 37 #include <sys/limits.h> 38 #include <sys/malloc.h> 39 40 #include <dev/drm2/drm_gem_names.h> 41 42 MALLOC_DEFINE(M_GEM_NAMES, "gem_name", "Hash headers for the gem names"); 43 44 static void drm_gem_names_delete_name(struct drm_gem_names *names, 45 struct drm_gem_name *np); 46 47 void 48 drm_gem_names_init(struct drm_gem_names *names) 49 { 50 51 names->unr = new_unrhdr(1, INT_MAX, NULL); /* XXXKIB */ 52 names->names_hash = hashinit(1000 /* XXXKIB */, M_GEM_NAMES, 53 &names->hash_mask); 54 mtx_init(&names->lock, "drmnames", NULL, MTX_DEF); 55 } 56 57 void 58 drm_gem_names_fini(struct drm_gem_names *names) 59 { 60 struct drm_gem_name *np; 61 int i; 62 63 mtx_lock(&names->lock); 64 for (i = 0; i <= names->hash_mask; i++) { 65 while ((np = LIST_FIRST(&names->names_hash[i])) != NULL) { 66 drm_gem_names_delete_name(names, np); 67 mtx_lock(&names->lock); 68 } 69 } 70 mtx_unlock(&names->lock); 71 mtx_destroy(&names->lock); 72 hashdestroy(names->names_hash, M_GEM_NAMES, names->hash_mask); 73 delete_unrhdr(names->unr); 74 } 75 76 static struct drm_gem_names_head * 77 gem_name_hash_index(struct drm_gem_names *names, int name) 78 { 79 80 return (&names->names_hash[name & names->hash_mask]); 81 } 82 83 void * 84 drm_gem_name_ref(struct drm_gem_names *names, uint32_t name, 85 void (*ref)(void *)) 86 { 87 struct drm_gem_name *n; 88 89 mtx_lock(&names->lock); 90 LIST_FOREACH(n, gem_name_hash_index(names, name), link) { 91 if (n->name == name) { 92 if (ref != NULL) 93 ref(n->ptr); 94 mtx_unlock(&names->lock); 95 return (n->ptr); 96 } 97 } 98 mtx_unlock(&names->lock); 99 return (NULL); 100 } 101 102 struct drm_gem_ptr_match_arg { 103 uint32_t res; 104 void *ptr; 105 }; 106 107 static int 108 drm_gem_ptr_match(uint32_t name, void *ptr, void *arg) 109 { 110 struct drm_gem_ptr_match_arg *a; 111 112 a = arg; 113 if (ptr == a->ptr) { 114 a->res = name; 115 return (1); 116 } else 117 return (0); 118 } 119 120 uint32_t 121 drm_gem_find_name(struct drm_gem_names *names, void *ptr) 122 { 123 struct drm_gem_ptr_match_arg arg; 124 125 arg.res = 0; 126 arg.ptr = ptr; 127 drm_gem_names_foreach(names, drm_gem_ptr_match, &arg); 128 return (arg.res); 129 } 130 131 void * 132 drm_gem_find_ptr(struct drm_gem_names *names, uint32_t name) 133 { 134 struct drm_gem_name *n; 135 void *res; 136 137 mtx_lock(&names->lock); 138 LIST_FOREACH(n, gem_name_hash_index(names, name), link) { 139 if (n->name == name) { 140 res = n->ptr; 141 mtx_unlock(&names->lock); 142 return (res); 143 } 144 } 145 mtx_unlock(&names->lock); 146 return (NULL); 147 } 148 149 int 150 drm_gem_name_create(struct drm_gem_names *names, void *p, uint32_t *name) 151 { 152 struct drm_gem_name *np; 153 154 if (*name != 0) { 155 return (-EALREADY); 156 } 157 158 np = malloc(sizeof(struct drm_gem_name), M_GEM_NAMES, M_WAITOK); 159 mtx_lock(&names->lock); 160 np->name = alloc_unr(names->unr); 161 if (np->name == -1) { 162 mtx_unlock(&names->lock); 163 free(np, M_GEM_NAMES); 164 return (-ENOMEM); 165 } 166 *name = np->name; 167 np->ptr = p; 168 LIST_INSERT_HEAD(gem_name_hash_index(names, np->name), np, link); 169 mtx_unlock(&names->lock); 170 return (0); 171 } 172 173 static void 174 drm_gem_names_delete_name(struct drm_gem_names *names, struct drm_gem_name *np) 175 { 176 177 mtx_assert(&names->lock, MA_OWNED); 178 LIST_REMOVE(np, link); 179 mtx_unlock(&names->lock); 180 free_unr(names->unr, np->name); 181 free(np, M_GEM_NAMES); 182 } 183 184 void * 185 drm_gem_names_remove(struct drm_gem_names *names, uint32_t name) 186 { 187 struct drm_gem_name *n; 188 void *res; 189 190 mtx_lock(&names->lock); 191 LIST_FOREACH(n, gem_name_hash_index(names, name), link) { 192 if (n->name == name) { 193 res = n->ptr; 194 drm_gem_names_delete_name(names, n); 195 return (res); 196 } 197 } 198 mtx_unlock(&names->lock); 199 return (NULL); 200 } 201 202 void 203 drm_gem_names_foreach(struct drm_gem_names *names, 204 int (*f)(uint32_t, void *, void *), void *arg) 205 { 206 struct drm_gem_name *np; 207 struct drm_gem_name marker; 208 int i, fres; 209 210 bzero(&marker, sizeof(marker)); 211 marker.name = -1; 212 mtx_lock(&names->lock); 213 for (i = 0; i <= names->hash_mask; i++) { 214 for (np = LIST_FIRST(&names->names_hash[i]); np != NULL; ) { 215 if (np->name == -1) { 216 np = LIST_NEXT(np, link); 217 continue; 218 } 219 LIST_INSERT_AFTER(np, &marker, link); 220 mtx_unlock(&names->lock); 221 fres = f(np->name, np->ptr, arg); 222 mtx_lock(&names->lock); 223 np = LIST_NEXT(&marker, link); 224 LIST_REMOVE(&marker, link); 225 if (fres) 226 break; 227 } 228 } 229 mtx_unlock(&names->lock); 230 } 231