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