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