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