1 1.2 riastrad /* $NetBSD: drm_hashtab.c,v 1.3 2021/12/18 23:44:57 riastradh Exp $ */ 2 1.2 riastrad 3 1.1 riastrad /************************************************************************** 4 1.1 riastrad * 5 1.1 riastrad * Copyright 2006 Tungsten Graphics, Inc., Bismarck, ND. USA. 6 1.1 riastrad * All Rights Reserved. 7 1.1 riastrad * 8 1.1 riastrad * Permission is hereby granted, free of charge, to any person obtaining a 9 1.1 riastrad * copy of this software and associated documentation files (the 10 1.1 riastrad * "Software"), to deal in the Software without restriction, including 11 1.1 riastrad * without limitation the rights to use, copy, modify, merge, publish, 12 1.1 riastrad * distribute, sub license, and/or sell copies of the Software, and to 13 1.1 riastrad * permit persons to whom the Software is furnished to do so, subject to 14 1.1 riastrad * the following conditions: 15 1.1 riastrad * 16 1.1 riastrad * The above copyright notice and this permission notice (including the 17 1.1 riastrad * next paragraph) shall be included in all copies or substantial portions 18 1.1 riastrad * of the Software. 19 1.1 riastrad * 20 1.1 riastrad * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 21 1.1 riastrad * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 22 1.1 riastrad * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL 23 1.1 riastrad * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, 24 1.1 riastrad * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 25 1.1 riastrad * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 26 1.1 riastrad * USE OR OTHER DEALINGS IN THE SOFTWARE. 27 1.1 riastrad * 28 1.1 riastrad * 29 1.1 riastrad **************************************************************************/ 30 1.1 riastrad /* 31 1.1 riastrad * Simple open hash tab implementation. 32 1.1 riastrad * 33 1.1 riastrad * Authors: 34 1.1 riastrad * Thomas Hellstrm <thomas-at-tungstengraphics-dot-com> 35 1.1 riastrad */ 36 1.1 riastrad 37 1.2 riastrad #include <sys/cdefs.h> 38 1.2 riastrad __KERNEL_RCSID(0, "$NetBSD: drm_hashtab.c,v 1.3 2021/12/18 23:44:57 riastradh Exp $"); 39 1.2 riastrad 40 1.3 riastrad #include <linux/export.h> 41 1.1 riastrad #include <linux/hash.h> 42 1.3 riastrad #include <linux/mm.h> 43 1.3 riastrad #include <linux/rculist.h> 44 1.1 riastrad #include <linux/slab.h> 45 1.3 riastrad #include <linux/vmalloc.h> 46 1.3 riastrad 47 1.3 riastrad #include <drm/drm_hashtab.h> 48 1.3 riastrad #include <drm/drm_print.h> 49 1.1 riastrad 50 1.1 riastrad int drm_ht_create(struct drm_open_hash *ht, unsigned int order) 51 1.1 riastrad { 52 1.1 riastrad unsigned int size = 1 << order; 53 1.1 riastrad 54 1.1 riastrad ht->order = order; 55 1.1 riastrad ht->table = NULL; 56 1.1 riastrad if (size <= PAGE_SIZE / sizeof(*ht->table)) 57 1.1 riastrad ht->table = kcalloc(size, sizeof(*ht->table), GFP_KERNEL); 58 1.1 riastrad else 59 1.3 riastrad ht->table = vzalloc(array_size(size, sizeof(*ht->table))); 60 1.1 riastrad if (!ht->table) { 61 1.1 riastrad DRM_ERROR("Out of memory for hash table\n"); 62 1.1 riastrad return -ENOMEM; 63 1.1 riastrad } 64 1.1 riastrad return 0; 65 1.1 riastrad } 66 1.1 riastrad EXPORT_SYMBOL(drm_ht_create); 67 1.1 riastrad 68 1.1 riastrad void drm_ht_verbose_list(struct drm_open_hash *ht, unsigned long key) 69 1.1 riastrad { 70 1.1 riastrad struct drm_hash_item *entry; 71 1.1 riastrad struct hlist_head *h_list; 72 1.1 riastrad unsigned int hashed_key; 73 1.1 riastrad int count = 0; 74 1.1 riastrad 75 1.1 riastrad hashed_key = hash_long(key, ht->order); 76 1.1 riastrad DRM_DEBUG("Key is 0x%08lx, Hashed key is 0x%08x\n", key, hashed_key); 77 1.1 riastrad h_list = &ht->table[hashed_key]; 78 1.2 riastrad hlist_for_each_entry(entry, h_list, head) 79 1.1 riastrad DRM_DEBUG("count %d, key: 0x%08lx\n", count++, entry->key); 80 1.1 riastrad } 81 1.1 riastrad 82 1.1 riastrad static struct hlist_node *drm_ht_find_key(struct drm_open_hash *ht, 83 1.1 riastrad unsigned long key) 84 1.1 riastrad { 85 1.1 riastrad struct drm_hash_item *entry; 86 1.1 riastrad struct hlist_head *h_list; 87 1.1 riastrad unsigned int hashed_key; 88 1.1 riastrad 89 1.1 riastrad hashed_key = hash_long(key, ht->order); 90 1.1 riastrad h_list = &ht->table[hashed_key]; 91 1.2 riastrad hlist_for_each_entry(entry, h_list, head) { 92 1.1 riastrad if (entry->key == key) 93 1.2 riastrad return &entry->head; 94 1.1 riastrad if (entry->key > key) 95 1.1 riastrad break; 96 1.1 riastrad } 97 1.1 riastrad return NULL; 98 1.1 riastrad } 99 1.1 riastrad 100 1.1 riastrad static struct hlist_node *drm_ht_find_key_rcu(struct drm_open_hash *ht, 101 1.1 riastrad unsigned long key) 102 1.1 riastrad { 103 1.1 riastrad struct drm_hash_item *entry; 104 1.1 riastrad struct hlist_head *h_list; 105 1.1 riastrad unsigned int hashed_key; 106 1.1 riastrad 107 1.1 riastrad hashed_key = hash_long(key, ht->order); 108 1.1 riastrad h_list = &ht->table[hashed_key]; 109 1.2 riastrad hlist_for_each_entry_rcu(entry, h_list, head) { 110 1.1 riastrad if (entry->key == key) 111 1.2 riastrad return &entry->head; 112 1.1 riastrad if (entry->key > key) 113 1.1 riastrad break; 114 1.1 riastrad } 115 1.1 riastrad return NULL; 116 1.1 riastrad } 117 1.1 riastrad 118 1.1 riastrad int drm_ht_insert_item(struct drm_open_hash *ht, struct drm_hash_item *item) 119 1.1 riastrad { 120 1.1 riastrad struct drm_hash_item *entry; 121 1.1 riastrad struct hlist_head *h_list; 122 1.2 riastrad struct hlist_node *parent; 123 1.1 riastrad unsigned int hashed_key; 124 1.1 riastrad unsigned long key = item->key; 125 1.1 riastrad 126 1.1 riastrad hashed_key = hash_long(key, ht->order); 127 1.1 riastrad h_list = &ht->table[hashed_key]; 128 1.1 riastrad parent = NULL; 129 1.2 riastrad hlist_for_each_entry(entry, h_list, head) { 130 1.1 riastrad if (entry->key == key) 131 1.1 riastrad return -EINVAL; 132 1.1 riastrad if (entry->key > key) 133 1.1 riastrad break; 134 1.2 riastrad parent = &entry->head; 135 1.1 riastrad } 136 1.1 riastrad if (parent) { 137 1.2 riastrad hlist_add_behind_rcu(&item->head, parent); 138 1.1 riastrad } else { 139 1.1 riastrad hlist_add_head_rcu(&item->head, h_list); 140 1.1 riastrad } 141 1.1 riastrad return 0; 142 1.1 riastrad } 143 1.1 riastrad EXPORT_SYMBOL(drm_ht_insert_item); 144 1.1 riastrad 145 1.1 riastrad /* 146 1.1 riastrad * Just insert an item and return any "bits" bit key that hasn't been 147 1.1 riastrad * used before. 148 1.1 riastrad */ 149 1.1 riastrad int drm_ht_just_insert_please(struct drm_open_hash *ht, struct drm_hash_item *item, 150 1.1 riastrad unsigned long seed, int bits, int shift, 151 1.1 riastrad unsigned long add) 152 1.1 riastrad { 153 1.1 riastrad int ret; 154 1.3 riastrad unsigned long mask = (1UL << bits) - 1; 155 1.1 riastrad unsigned long first, unshifted_key; 156 1.1 riastrad 157 1.1 riastrad unshifted_key = hash_long(seed, bits); 158 1.1 riastrad first = unshifted_key; 159 1.1 riastrad do { 160 1.1 riastrad item->key = (unshifted_key << shift) + add; 161 1.1 riastrad ret = drm_ht_insert_item(ht, item); 162 1.1 riastrad if (ret) 163 1.1 riastrad unshifted_key = (unshifted_key + 1) & mask; 164 1.1 riastrad } while(ret && (unshifted_key != first)); 165 1.1 riastrad 166 1.1 riastrad if (ret) { 167 1.1 riastrad DRM_ERROR("Available key bit space exhausted\n"); 168 1.1 riastrad return -EINVAL; 169 1.1 riastrad } 170 1.1 riastrad return 0; 171 1.1 riastrad } 172 1.1 riastrad EXPORT_SYMBOL(drm_ht_just_insert_please); 173 1.1 riastrad 174 1.1 riastrad int drm_ht_find_item(struct drm_open_hash *ht, unsigned long key, 175 1.1 riastrad struct drm_hash_item **item) 176 1.1 riastrad { 177 1.1 riastrad struct hlist_node *list; 178 1.1 riastrad 179 1.1 riastrad list = drm_ht_find_key_rcu(ht, key); 180 1.1 riastrad if (!list) 181 1.1 riastrad return -EINVAL; 182 1.1 riastrad 183 1.1 riastrad *item = hlist_entry(list, struct drm_hash_item, head); 184 1.1 riastrad return 0; 185 1.1 riastrad } 186 1.1 riastrad EXPORT_SYMBOL(drm_ht_find_item); 187 1.1 riastrad 188 1.1 riastrad int drm_ht_remove_key(struct drm_open_hash *ht, unsigned long key) 189 1.1 riastrad { 190 1.1 riastrad struct hlist_node *list; 191 1.1 riastrad 192 1.1 riastrad list = drm_ht_find_key(ht, key); 193 1.1 riastrad if (list) { 194 1.1 riastrad hlist_del_init_rcu(list); 195 1.1 riastrad return 0; 196 1.1 riastrad } 197 1.1 riastrad return -EINVAL; 198 1.1 riastrad } 199 1.1 riastrad 200 1.1 riastrad int drm_ht_remove_item(struct drm_open_hash *ht, struct drm_hash_item *item) 201 1.1 riastrad { 202 1.1 riastrad hlist_del_init_rcu(&item->head); 203 1.1 riastrad return 0; 204 1.1 riastrad } 205 1.1 riastrad EXPORT_SYMBOL(drm_ht_remove_item); 206 1.1 riastrad 207 1.1 riastrad void drm_ht_remove(struct drm_open_hash *ht) 208 1.1 riastrad { 209 1.1 riastrad if (ht->table) { 210 1.3 riastrad kvfree(ht->table); 211 1.1 riastrad ht->table = NULL; 212 1.1 riastrad } 213 1.1 riastrad } 214 1.1 riastrad EXPORT_SYMBOL(drm_ht_remove); 215