Subversion Repositories Kolibri OS

Rev

Rev 5060 | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed

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