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