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