0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035 #include <linux/hash.h>
0036 #include <linux/mm.h>
0037 #include <linux/rculist.h>
0038 #include <linux/slab.h>
0039 #include <linux/vmalloc.h>
0040
0041 #include <drm/drm_print.h>
0042
0043 #include "drm_legacy.h"
0044
0045 int drm_ht_create(struct drm_open_hash *ht, unsigned int order)
0046 {
0047 unsigned int size = 1 << order;
0048
0049 ht->order = order;
0050 ht->table = NULL;
0051 if (size <= PAGE_SIZE / sizeof(*ht->table))
0052 ht->table = kcalloc(size, sizeof(*ht->table), GFP_KERNEL);
0053 else
0054 ht->table = vzalloc(array_size(size, sizeof(*ht->table)));
0055 if (!ht->table) {
0056 DRM_ERROR("Out of memory for hash table\n");
0057 return -ENOMEM;
0058 }
0059 return 0;
0060 }
0061
0062 void drm_ht_verbose_list(struct drm_open_hash *ht, unsigned long key)
0063 {
0064 struct drm_hash_item *entry;
0065 struct hlist_head *h_list;
0066 unsigned int hashed_key;
0067 int count = 0;
0068
0069 hashed_key = hash_long(key, ht->order);
0070 DRM_DEBUG("Key is 0x%08lx, Hashed key is 0x%08x\n", key, hashed_key);
0071 h_list = &ht->table[hashed_key];
0072 hlist_for_each_entry(entry, h_list, head)
0073 DRM_DEBUG("count %d, key: 0x%08lx\n", count++, entry->key);
0074 }
0075
0076 static struct hlist_node *drm_ht_find_key(struct drm_open_hash *ht,
0077 unsigned long key)
0078 {
0079 struct drm_hash_item *entry;
0080 struct hlist_head *h_list;
0081 unsigned int hashed_key;
0082
0083 hashed_key = hash_long(key, ht->order);
0084 h_list = &ht->table[hashed_key];
0085 hlist_for_each_entry(entry, h_list, head) {
0086 if (entry->key == key)
0087 return &entry->head;
0088 if (entry->key > key)
0089 break;
0090 }
0091 return NULL;
0092 }
0093
0094 static struct hlist_node *drm_ht_find_key_rcu(struct drm_open_hash *ht,
0095 unsigned long key)
0096 {
0097 struct drm_hash_item *entry;
0098 struct hlist_head *h_list;
0099 unsigned int hashed_key;
0100
0101 hashed_key = hash_long(key, ht->order);
0102 h_list = &ht->table[hashed_key];
0103 hlist_for_each_entry_rcu(entry, h_list, head) {
0104 if (entry->key == key)
0105 return &entry->head;
0106 if (entry->key > key)
0107 break;
0108 }
0109 return NULL;
0110 }
0111
0112 int drm_ht_insert_item(struct drm_open_hash *ht, struct drm_hash_item *item)
0113 {
0114 struct drm_hash_item *entry;
0115 struct hlist_head *h_list;
0116 struct hlist_node *parent;
0117 unsigned int hashed_key;
0118 unsigned long key = item->key;
0119
0120 hashed_key = hash_long(key, ht->order);
0121 h_list = &ht->table[hashed_key];
0122 parent = NULL;
0123 hlist_for_each_entry(entry, h_list, head) {
0124 if (entry->key == key)
0125 return -EINVAL;
0126 if (entry->key > key)
0127 break;
0128 parent = &entry->head;
0129 }
0130 if (parent) {
0131 hlist_add_behind_rcu(&item->head, parent);
0132 } else {
0133 hlist_add_head_rcu(&item->head, h_list);
0134 }
0135 return 0;
0136 }
0137
0138
0139
0140
0141
0142 int drm_ht_just_insert_please(struct drm_open_hash *ht, struct drm_hash_item *item,
0143 unsigned long seed, int bits, int shift,
0144 unsigned long add)
0145 {
0146 int ret;
0147 unsigned long mask = (1UL << bits) - 1;
0148 unsigned long first, unshifted_key;
0149
0150 unshifted_key = hash_long(seed, bits);
0151 first = unshifted_key;
0152 do {
0153 item->key = (unshifted_key << shift) + add;
0154 ret = drm_ht_insert_item(ht, item);
0155 if (ret)
0156 unshifted_key = (unshifted_key + 1) & mask;
0157 } while(ret && (unshifted_key != first));
0158
0159 if (ret) {
0160 DRM_ERROR("Available key bit space exhausted\n");
0161 return -EINVAL;
0162 }
0163 return 0;
0164 }
0165
0166 int drm_ht_find_item(struct drm_open_hash *ht, unsigned long key,
0167 struct drm_hash_item **item)
0168 {
0169 struct hlist_node *list;
0170
0171 list = drm_ht_find_key_rcu(ht, key);
0172 if (!list)
0173 return -EINVAL;
0174
0175 *item = hlist_entry(list, struct drm_hash_item, head);
0176 return 0;
0177 }
0178
0179 int drm_ht_remove_key(struct drm_open_hash *ht, unsigned long key)
0180 {
0181 struct hlist_node *list;
0182
0183 list = drm_ht_find_key(ht, key);
0184 if (list) {
0185 hlist_del_init_rcu(list);
0186 return 0;
0187 }
0188 return -EINVAL;
0189 }
0190
0191 int drm_ht_remove_item(struct drm_open_hash *ht, struct drm_hash_item *item)
0192 {
0193 hlist_del_init_rcu(&item->head);
0194 return 0;
0195 }
0196
0197 void drm_ht_remove(struct drm_open_hash *ht)
0198 {
0199 if (ht->table) {
0200 kvfree(ht->table);
0201 ht->table = NULL;
0202 }
0203 }