Subversion Repositories Kolibri OS

Rev

Rev 4104 | Go to most recent revision | 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. #include <linux/rculist.h>
  41.  
  42. #define hlist_for_each_entry_rcu(pos, head, member)                     \
  43.     for (pos = hlist_entry_safe (rcu_dereference_raw(hlist_first_rcu(head)),\
  44.                typeof(*(pos)), member);                        \
  45.             pos;                                                    \
  46.             pos = hlist_entry_safe(rcu_dereference_raw(hlist_next_rcu(\
  47.                   &(pos)->member)), typeof(*(pos)), member))
  48.  
  49.  
  50. int drm_ht_create(struct drm_open_hash *ht, unsigned int order)
  51. {
  52.         unsigned int size = 1 << order;
  53.  
  54.         ht->order = order;
  55.         ht->table = NULL;
  56.     ht->table = kcalloc(size, sizeof(*ht->table), GFP_KERNEL);
  57.         if (!ht->table) {
  58.                 DRM_ERROR("Out of memory for hash table\n");
  59.                 return -ENOMEM;
  60.         }
  61.         return 0;
  62. }
  63. EXPORT_SYMBOL(drm_ht_create);
  64.  
  65. void drm_ht_verbose_list(struct drm_open_hash *ht, unsigned long key)
  66. {
  67.         struct drm_hash_item *entry;
  68.         struct hlist_head *h_list;
  69.         unsigned int hashed_key;
  70.         int count = 0;
  71.  
  72.         hashed_key = hash_long(key, ht->order);
  73.         DRM_DEBUG("Key is 0x%08lx, Hashed key is 0x%08x\n", key, hashed_key);
  74.         h_list = &ht->table[hashed_key];
  75.         hlist_for_each_entry(entry, h_list, head)
  76.                 DRM_DEBUG("count %d, key: 0x%08lx\n", count++, entry->key);
  77. }
  78.  
  79. static struct hlist_node *drm_ht_find_key(struct drm_open_hash *ht,
  80.                                           unsigned long key)
  81. {
  82.         struct drm_hash_item *entry;
  83.         struct hlist_head *h_list;
  84.         unsigned int hashed_key;
  85.  
  86.         hashed_key = hash_long(key, ht->order);
  87.         h_list = &ht->table[hashed_key];
  88.         hlist_for_each_entry(entry, h_list, head) {
  89.                 if (entry->key == key)
  90.                         return &entry->head;
  91.                 if (entry->key > key)
  92.                         break;
  93.         }
  94.         return NULL;
  95. }
  96.  
  97.  
  98. static struct hlist_node *drm_ht_find_key_rcu(struct drm_open_hash *ht,
  99.                                               unsigned long key)
  100. {
  101.         struct drm_hash_item *entry;
  102.         struct hlist_head *h_list;
  103.         unsigned int hashed_key;
  104.  
  105.         hashed_key = hash_long(key, ht->order);
  106.         h_list = &ht->table[hashed_key];
  107.         hlist_for_each_entry_rcu(entry, h_list, head) {
  108.                 if (entry->key == key)
  109.                         return &entry->head;
  110.                 if (entry->key > key)
  111.                         break;
  112.         }
  113.         return NULL;
  114. }
  115.  
  116. int drm_ht_insert_item(struct drm_open_hash *ht, struct drm_hash_item *item)
  117. {
  118.         struct drm_hash_item *entry;
  119.         struct hlist_head *h_list;
  120.         struct hlist_node *parent;
  121.         unsigned int hashed_key;
  122.         unsigned long key = item->key;
  123.  
  124.         hashed_key = hash_long(key, ht->order);
  125.         h_list = &ht->table[hashed_key];
  126.         parent = NULL;
  127.         hlist_for_each_entry(entry, h_list, head) {
  128.                 if (entry->key == key)
  129.                         return -EINVAL;
  130.                 if (entry->key > key)
  131.                         break;
  132.                 parent = &entry->head;
  133.         }
  134.         if (parent) {
  135.                 hlist_add_after_rcu(parent, &item->head);
  136.         } else {
  137.                 hlist_add_head_rcu(&item->head, h_list);
  138.         }
  139.         return 0;
  140. }
  141. EXPORT_SYMBOL(drm_ht_insert_item);
  142.  
  143. /*
  144.  * Just insert an item and return any "bits" bit key that hasn't been
  145.  * used before.
  146.  */
  147. int drm_ht_just_insert_please(struct drm_open_hash *ht, struct drm_hash_item *item,
  148.                               unsigned long seed, int bits, int shift,
  149.                               unsigned long add)
  150. {
  151.         int ret;
  152.         unsigned long mask = (1 << bits) - 1;
  153.         unsigned long first, unshifted_key;
  154.  
  155.         unshifted_key = hash_long(seed, bits);
  156.         first = unshifted_key;
  157.         do {
  158.                 item->key = (unshifted_key << shift) + add;
  159.                 ret = drm_ht_insert_item(ht, item);
  160.                 if (ret)
  161.                         unshifted_key = (unshifted_key + 1) & mask;
  162.         } while(ret && (unshifted_key != first));
  163.  
  164.         if (ret) {
  165.                 DRM_ERROR("Available key bit space exhausted\n");
  166.                 return -EINVAL;
  167.         }
  168.         return 0;
  169. }
  170. EXPORT_SYMBOL(drm_ht_just_insert_please);
  171.  
  172. int drm_ht_find_item(struct drm_open_hash *ht, unsigned long key,
  173.                      struct drm_hash_item **item)
  174. {
  175.         struct hlist_node *list;
  176.  
  177.         list = drm_ht_find_key_rcu(ht, key);
  178.         if (!list)
  179.                 return -EINVAL;
  180.  
  181.         *item = hlist_entry(list, struct drm_hash_item, head);
  182.         return 0;
  183. }
  184. EXPORT_SYMBOL(drm_ht_find_item);
  185.  
  186. int drm_ht_remove_key(struct drm_open_hash *ht, unsigned long key)
  187. {
  188.         struct hlist_node *list;
  189.  
  190.         list = drm_ht_find_key(ht, key);
  191.         if (list) {
  192.                 hlist_del_init_rcu(list);
  193.                 return 0;
  194.         }
  195.         return -EINVAL;
  196. }
  197.  
  198. int drm_ht_remove_item(struct drm_open_hash *ht, struct drm_hash_item *item)
  199. {
  200.         hlist_del_init_rcu(&item->head);
  201.         return 0;
  202. }
  203. EXPORT_SYMBOL(drm_ht_remove_item);
  204.  
  205. void drm_ht_remove(struct drm_open_hash *ht)
  206. {
  207.         if (ht->table) {
  208.         kfree(ht->table);
  209.                 ht->table = NULL;
  210.         }
  211. }
  212. EXPORT_SYMBOL(drm_ht_remove);
  213.