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