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/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 39 MALLOC_DEFINE(M_GEM_NAMES, "gem_name", "Hash headers for the gem names"); 40 41 static void drm_gem_names_delete_name(struct drm_gem_names *names, 42 struct drm_gem_name *np); 43 44 void 45 drm_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 54 void 55 drm_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 73 static struct drm_gem_names_head * 74 gem_name_hash_index(struct drm_gem_names *names, int name) 75 { 76 77 return (&names->names_hash[name & names->hash_mask]); 78 } 79 80 void * 81 drm_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 99 struct drm_gem_ptr_match_arg { 100 uint32_t res; 101 void *ptr; 102 }; 103 104 static int 105 drm_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 117 uint32_t 118 drm_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 128 void * 129 drm_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 146 int 147 drm_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 170 static void 171 drm_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 181 void * 182 drm_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 199 void 200 drm_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