qdf_ptr_hash.h 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311
  1. /*
  2. * Copyright (c) 2019 The Linux Foundation. All rights reserved.
  3. *
  4. * Permission to use, copy, modify, and/or distribute this software for
  5. * any purpose with or without fee is hereby granted, provided that the
  6. * above copyright notice and this permission notice appear in all
  7. * copies.
  8. *
  9. * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
  10. * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
  11. * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
  12. * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
  13. * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
  14. * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
  15. * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
  16. * PERFORMANCE OF THIS SOFTWARE.
  17. */
  18. /**
  19. * DOC: qdf_ptr_hash.h
  20. *
  21. * A minimal hashtable implementation for doing fast lookups via pointer.
  22. *
  23. * qdf_ptr_hash also has the benefit of knowing its own size, allowing a pointer
  24. * to the hashtable to be passed around and embedded in other structs. Since
  25. * every hashtable is not necessarily of the same size, this allows using hash
  26. * tables in a lot of new places which would be impossible with the current
  27. * kernel hashtable implementation.
  28. *
  29. * Because the size of the hashtable varies with the number of bits used in the
  30. * hash, declaring a qdf_ptr_hash is a bit different. If you want to embed a
  31. * qdf_ptr_hash in another type, use a combination of qdf_ptr_hash_declare() and
  32. * qdf_ptr_hash_ptr(). If you just want to declare and use a qdf_ptr_hash, use
  33. * qdf_ptr_hash_declare_ptr() instead. Either method will ensure the appropriate
  34. * number of bytes is accounted for using an internal union, and provides the
  35. * consumer with a pointer to a qdf_ptr_hash type which can be used with all of
  36. * the other qdf_ptr_hash APIs. Alternatively, you can skip these complexities
  37. * by simply dynamically allocating the qdf_ptr_hash via qdf_ptr_hash_create().
  38. */
  39. #ifndef __QDF_PTR_HASH_H
  40. #define __QDF_PTR_HASH_H
  41. #include "i_qdf_ptr_hash.h"
  42. #include "qdf_mem.h"
  43. #include "qdf_slist.h"
  44. #include "qdf_types.h"
  45. #include "qdf_util.h"
  46. /**
  47. * struct qdf_ptr_hash_bucket - a type representing a hash bucket
  48. * @list: the list used for hash chaining
  49. */
  50. struct qdf_ptr_hash_bucket {
  51. struct qdf_slist list;
  52. };
  53. /**
  54. * struct qdf_ptr_hash - a hash table type for doing fast lookups via pointer
  55. * @bits: the number of bits to use when hashing keys
  56. * @count: the number of buckets, always equal to 2^@bits
  57. * @buckets: empty bucket array for accessing a variable length array of buckets
  58. */
  59. struct qdf_ptr_hash {
  60. int8_t bits;
  61. int16_t count;
  62. struct qdf_ptr_hash_bucket buckets[0];
  63. };
  64. /**
  65. * struct qdf_ptr_hash_entry - entry type of membership in a qdf_ptr_hash
  66. * @key: the value used as the key for insertion/lookup
  67. * @node: the list node used for hash chaining
  68. */
  69. struct qdf_ptr_hash_entry {
  70. uintptr_t key;
  71. struct qdf_slist_node node;
  72. };
  73. #define __qdf_ptr_hash_size(bits) (sizeof(struct qdf_ptr_hash) + \
  74. sizeof(((struct qdf_ptr_hash *)0)->buckets[0]) * (1 << bits))
  75. /**
  76. * qdf_ptr_hash_declare() - declare a new qdf_ptr_hash
  77. * @name: the C identifier to use for the new hash table
  78. * @bits: The number of bits to use for hashing
  79. *
  80. * Return: None
  81. */
  82. #define qdf_ptr_hash_declare(name, _bits) \
  83. union { \
  84. struct qdf_ptr_hash ht; \
  85. uint8_t __raw[__qdf_ptr_hash_size(_bits)]; \
  86. } __##name = { .ht = { .bits = _bits, .count = (1 << _bits) } }
  87. /**
  88. * qdf_ptr_hash_ptr() - get a pointer to a declared qdf_ptr_hash
  89. * @name: the C identifier of the declared qdf_ptr_hash
  90. *
  91. * Return: pointer to a qdf_ptr_hash
  92. */
  93. #define qdf_ptr_hash_ptr(name) &__##name.ht
  94. /**
  95. * qdf_ptr_hash_declare_ptr() - declare a pointer to a new qdf_ptr_hash
  96. * @name: the C identifier to use for the pointer to the new qdf_ptr_hash
  97. * @bits: The number of bits to use for hashing
  98. *
  99. * Return: None
  100. */
  101. #define qdf_ptr_hash_declare_ptr(name, bits) \
  102. qdf_ptr_hash_declare(name, bits); \
  103. struct qdf_ptr_hash *name = qdf_ptr_hash_ptr(name)
  104. #define __qdf_ptr_hash_for_each_bucket(ht, bkt) \
  105. for ((bkt) = (ht)->buckets; \
  106. (bkt) < (ht)->buckets + (ht)->count; \
  107. (bkt)++)
  108. /**
  109. * qdf_ptr_hash_init() - initialize a qdf_ptr_hash
  110. * @ht: the hash table to initialize
  111. *
  112. * Return: None
  113. */
  114. static inline void qdf_ptr_hash_init(struct qdf_ptr_hash *ht)
  115. {
  116. struct qdf_ptr_hash_bucket *bucket;
  117. __qdf_ptr_hash_for_each_bucket(ht, bucket)
  118. qdf_slist_init(&bucket->list);
  119. }
  120. /**
  121. * qdf_ptr_hash_deinit() - de-initialize a qdf_ptr_hash
  122. * @ht: the hash table to de-initialize
  123. *
  124. * Return: None
  125. */
  126. static inline void qdf_ptr_hash_deinit(struct qdf_ptr_hash *ht)
  127. {
  128. struct qdf_ptr_hash_bucket *bucket;
  129. __qdf_ptr_hash_for_each_bucket(ht, bucket)
  130. qdf_slist_deinit(&bucket->list);
  131. }
  132. /**
  133. * qdf_ptr_hash_create() - allocate and initialize a qdf_ptr_hash
  134. * @bits: the number of bits to use for hashing
  135. *
  136. * Return: qdf_ptr_hash pointer on succes, NULL on allocation failure
  137. */
  138. static inline struct qdf_ptr_hash *qdf_ptr_hash_create(uint8_t bits)
  139. {
  140. struct qdf_ptr_hash *ht = qdf_mem_malloc(__qdf_ptr_hash_size(bits));
  141. if (!ht)
  142. return NULL;
  143. ht->bits = bits;
  144. ht->count = 1 << bits;
  145. qdf_ptr_hash_init(ht);
  146. return ht;
  147. }
  148. /**
  149. * qdf_ptr_hash_destroy() - de-initialize and de-allocate a qdf_ptr_hash
  150. * @ht: the qdf_ptr_hash to destroy
  151. *
  152. * Return: None
  153. */
  154. static inline void qdf_ptr_hash_destroy(struct qdf_ptr_hash *ht)
  155. {
  156. qdf_ptr_hash_deinit(ht);
  157. qdf_mem_free(ht);
  158. }
  159. /**
  160. * qdf_ptr_hash_empty() - check if a qdf_ptr_hash has any entries
  161. * @ht: the qdf_ptr_hash to check
  162. *
  163. * Return: true if @ht contains no entries
  164. */
  165. static inline bool qdf_ptr_hash_empty(struct qdf_ptr_hash *ht)
  166. {
  167. struct qdf_ptr_hash_bucket *bucket;
  168. __qdf_ptr_hash_for_each_bucket(ht, bucket)
  169. if (!qdf_slist_empty(&bucket->list))
  170. return false;
  171. return true;
  172. }
  173. static inline struct qdf_ptr_hash_bucket *
  174. __qdf_ptr_hash_get_bucket(struct qdf_ptr_hash *ht, uintptr_t key)
  175. {
  176. return ht->buckets + __qdf_ptr_hash_key(key, ht->bits);
  177. }
  178. /**
  179. * qdf_ptr_hash_add() - insert an entry into a qdf_ptr_hash
  180. * @ht: the qdf_ptr_hash to insert into
  181. * @key: the pointer to use as an insertion/lookup key
  182. * @item: a pointer to a type that contains a qdf_ptr_hash_entry
  183. * @entry_field: C identifier for the qdf_ptr_hash_entry field in @item
  184. *
  185. * Return: None
  186. */
  187. #define qdf_ptr_hash_add(ht, key, item, entry_field) \
  188. __qdf_ptr_hash_add(ht, (uintptr_t)key, &(item)->entry_field)
  189. static inline void __qdf_ptr_hash_add(struct qdf_ptr_hash *ht, uintptr_t key,
  190. struct qdf_ptr_hash_entry *entry)
  191. {
  192. entry->key = key;
  193. qdf_slist_push(&__qdf_ptr_hash_get_bucket(ht, key)->list, entry, node);
  194. }
  195. /**
  196. * qdf_ptr_hash_remove() - remove an entry from a qdf_ptr_hash
  197. * @ht: the qdf_ptr_hash to remove from
  198. * @key: the pointer to use as a lookup key
  199. * @cursor: a pointer to a type that contains a qdf_ptr_hash_entry
  200. * @entry_field: C identifier for the qdf_ptr_hash_entry field in @cursor
  201. *
  202. * Return: removed item of type @cursor on success, NULL otherwise
  203. */
  204. #define qdf_ptr_hash_remove(ht, key, cursor, entry_field) ({ \
  205. struct qdf_ptr_hash_entry *_e = \
  206. __qdf_ptr_hash_remove(ht, (uintptr_t)key); \
  207. cursor = _e ? qdf_container_of(_e, typeof(*(cursor)), \
  208. entry_field) : NULL; \
  209. cursor; })
  210. static inline struct qdf_ptr_hash_entry *
  211. __qdf_ptr_hash_remove(struct qdf_ptr_hash *ht, uintptr_t key)
  212. {
  213. struct qdf_ptr_hash_bucket *bucket = __qdf_ptr_hash_get_bucket(ht, key);
  214. struct qdf_ptr_hash_entry *prev;
  215. struct qdf_ptr_hash_entry *entry;
  216. qdf_slist_for_each_del(&bucket->list, prev, entry, node) {
  217. if (entry->key == key) {
  218. qdf_slist_remove(&bucket->list, prev, node);
  219. entry->key = 0;
  220. return entry;
  221. }
  222. }
  223. return NULL;
  224. }
  225. #define __qdf_ptr_hash_for_each_in_bucket(bucket, cursor, entry_field) \
  226. qdf_slist_for_each(&(bucket)->list, cursor, entry_field.node)
  227. /**
  228. * qdf_ptr_hash_for_each() - qdf_ptr_hash item iterator for all items
  229. * @ht: the qdf_ptr_hash to iterate over
  230. * @bucket: qdf_ptr_hash_bucket cursor pointer
  231. * @cursor: a pointer to a type that contains a qdf_ptr_hash_entry
  232. * @entry_field: C identifier for the qdf_ptr_hash_entry field in @cursor
  233. */
  234. #define qdf_ptr_hash_for_each(ht, bucket, cursor, entry_field) \
  235. __qdf_ptr_hash_for_each_bucket(ht, bucket) \
  236. __qdf_ptr_hash_for_each_in_bucket(bucket, cursor, entry_field)
  237. /**
  238. * qdf_ptr_hash_for_each_by_hash() - qdf_ptr_hash item iterator for items which
  239. * hash to the same value as @key
  240. * @ht: the qdf_ptr_hash to iterate over
  241. * @key: the pointer to use as a lookup key
  242. * @cursor: a pointer to a type that contains a qdf_ptr_hash_entry
  243. * @entry_field: C identifier for the qdf_ptr_hash_entry field in @cursor
  244. */
  245. #define qdf_ptr_hash_for_each_by_hash(ht, key, cursor, entry_field) \
  246. __qdf_ptr_hash_for_each_in_bucket( \
  247. __qdf_ptr_hash_get_bucket(ht, (uintptr_t)key), \
  248. cursor, entry_field)
  249. /**
  250. * qdf_ptr_hash_for_each_by_key() - qdf_ptr_hash item iterator for items whose
  251. * keys equal @key
  252. * @ht: the qdf_ptr_hash to iterate over
  253. * @key: the pointer to use as a lookup key
  254. * @cursor: a pointer to a type that contains a qdf_ptr_hash_entry
  255. * @entry_field: C identifier for the qdf_ptr_hash_entry field in @cursor
  256. */
  257. #define qdf_ptr_hash_for_each_by_key(ht, _key, cursor, entry_field) \
  258. qdf_ptr_hash_for_each_by_hash(ht, _key, cursor, entry_field) \
  259. if ((cursor)->entry_field.key == (uintptr_t)_key)
  260. /**
  261. * qdf_ptr_hash_get() - get the first item whose key matches @key
  262. * @ht: the qdf_ptr_hash to look in
  263. * @key: the pointer to use as a lookup key
  264. * @cursor: a pointer to a type that contains a qdf_ptr_hash_entry
  265. * @entry_field: C identifier for the qdf_ptr_hash_entry field in @cursor
  266. *
  267. * Return: first item matching @key of type @cursor on success, NULL otherwise
  268. */
  269. #define qdf_ptr_hash_get(ht, key, cursor, entry_field) ({ \
  270. cursor = NULL; \
  271. qdf_ptr_hash_for_each_by_key(ht, key, cursor, entry_field) \
  272. break; \
  273. cursor; })
  274. #endif /* __QDF_PTR_HASH_H */