xref: /linux/drivers/infiniband/hw/efa/efa_ah_cache.c (revision 21bd0802cd3f58b656065f1be236694c40588c3a)
197ba1527SYonatan Nachum // SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause
297ba1527SYonatan Nachum /*
397ba1527SYonatan Nachum  * Copyright 2026 Amazon.com, Inc. or its affiliates. All rights reserved.
497ba1527SYonatan Nachum  */
597ba1527SYonatan Nachum 
697ba1527SYonatan Nachum #include <linux/slab.h>
797ba1527SYonatan Nachum 
897ba1527SYonatan Nachum #include "efa_ah_cache.h"
997ba1527SYonatan Nachum 
1097ba1527SYonatan Nachum static const struct rhashtable_params ah_cache_params = {
1197ba1527SYonatan Nachum 	.key_len = sizeof(struct efa_ah_cache_key),
1297ba1527SYonatan Nachum 	.key_offset = offsetof(struct efa_ah_cache_entry, key),
1397ba1527SYonatan Nachum 	.head_offset = offsetof(struct efa_ah_cache_entry, linkage),
1497ba1527SYonatan Nachum };
1597ba1527SYonatan Nachum 
1697ba1527SYonatan Nachum int efa_ah_cache_init(struct efa_ah_cache *ah_cache)
1797ba1527SYonatan Nachum {
1897ba1527SYonatan Nachum 	int err;
1997ba1527SYonatan Nachum 
2097ba1527SYonatan Nachum 	mutex_init(&ah_cache->lock);
2197ba1527SYonatan Nachum 	err = rhashtable_init(&ah_cache->hashtable, &ah_cache_params);
2297ba1527SYonatan Nachum 	if (err)
2397ba1527SYonatan Nachum 		mutex_destroy(&ah_cache->lock);
2497ba1527SYonatan Nachum 
2597ba1527SYonatan Nachum 	return err;
2697ba1527SYonatan Nachum }
2797ba1527SYonatan Nachum 
2897ba1527SYonatan Nachum static void efa_ah_cache_entry_free(void *ptr, void *arg)
2997ba1527SYonatan Nachum {
3097ba1527SYonatan Nachum 	struct efa_ah_cache_entry *entry = ptr;
3197ba1527SYonatan Nachum 
3297ba1527SYonatan Nachum 	WARN_ON(entry->usecnt);
3397ba1527SYonatan Nachum 	mutex_destroy(&entry->lock);
3497ba1527SYonatan Nachum 	kfree(entry);
3597ba1527SYonatan Nachum }
3697ba1527SYonatan Nachum 
3797ba1527SYonatan Nachum void efa_ah_cache_destroy(struct efa_ah_cache *ah_cache)
3897ba1527SYonatan Nachum {
3997ba1527SYonatan Nachum 	rhashtable_free_and_destroy(&ah_cache->hashtable, efa_ah_cache_entry_free, NULL);
4097ba1527SYonatan Nachum 	mutex_destroy(&ah_cache->lock);
4197ba1527SYonatan Nachum }
42*234895faSYonatan Nachum 
43*234895faSYonatan Nachum static struct efa_ah_cache_entry *efa_ah_cache_lookup_locked(struct efa_ah_cache *ah_cache, u16 pd,
44*234895faSYonatan Nachum 							     u8 *gid)
45*234895faSYonatan Nachum 	__must_hold(&ah_cache->lock)
46*234895faSYonatan Nachum {
47*234895faSYonatan Nachum 	struct efa_ah_cache_key key = {};
48*234895faSYonatan Nachum 
49*234895faSYonatan Nachum 	memcpy(key.gid, gid, sizeof(key.gid));
50*234895faSYonatan Nachum 	key.pd = pd;
51*234895faSYonatan Nachum 
52*234895faSYonatan Nachum 	return rhashtable_lookup_fast(&ah_cache->hashtable, &key, ah_cache_params);
53*234895faSYonatan Nachum }
54*234895faSYonatan Nachum 
55*234895faSYonatan Nachum struct efa_ah_cache_entry *efa_ah_cache_lookup(struct efa_ah_cache *ah_cache, u16 pd, u8 *gid)
56*234895faSYonatan Nachum {
57*234895faSYonatan Nachum 	struct efa_ah_cache_entry *entry;
58*234895faSYonatan Nachum 
59*234895faSYonatan Nachum 	mutex_lock(&ah_cache->lock);
60*234895faSYonatan Nachum 	entry = efa_ah_cache_lookup_locked(ah_cache, pd, gid);
61*234895faSYonatan Nachum 	mutex_unlock(&ah_cache->lock);
62*234895faSYonatan Nachum 
63*234895faSYonatan Nachum 	return entry;
64*234895faSYonatan Nachum }
65*234895faSYonatan Nachum 
66*234895faSYonatan Nachum /**
67*234895faSYonatan Nachum  * efa_ah_cache_get - Get or create an AH cache entry
68*234895faSYonatan Nachum  * @ah_cache: AH cache
69*234895faSYonatan Nachum  * @pd: Protection domain number
70*234895faSYonatan Nachum  * @gid: GID address
71*234895faSYonatan Nachum  *
72*234895faSYonatan Nachum  * Look up an AH cache entry by PD and GID. If found, take a reference and
73*234895faSYonatan Nachum  * return it. If not found, allocate a new entry and insert it. The caller must lock
74*234895faSYonatan Nachum  * the entry mutex and check usecnt to determine whether a device create
75*234895faSYonatan Nachum  * command is needed.
76*234895faSYonatan Nachum  *
77*234895faSYonatan Nachum  * Return: Pointer to the entry on success, ERR_PTR on failure.
78*234895faSYonatan Nachum  */
79*234895faSYonatan Nachum struct efa_ah_cache_entry *efa_ah_cache_get(struct efa_ah_cache *ah_cache, u16 pd, u8 *gid)
80*234895faSYonatan Nachum {
81*234895faSYonatan Nachum 	struct efa_ah_cache_entry *entry;
82*234895faSYonatan Nachum 	int err;
83*234895faSYonatan Nachum 
84*234895faSYonatan Nachum 	mutex_lock(&ah_cache->lock);
85*234895faSYonatan Nachum 
86*234895faSYonatan Nachum 	entry = efa_ah_cache_lookup_locked(ah_cache, pd, gid);
87*234895faSYonatan Nachum 	if (entry) {
88*234895faSYonatan Nachum 		refcount_inc(&entry->refcount);
89*234895faSYonatan Nachum 		mutex_unlock(&ah_cache->lock);
90*234895faSYonatan Nachum 		return entry;
91*234895faSYonatan Nachum 	}
92*234895faSYonatan Nachum 
93*234895faSYonatan Nachum 	entry = kzalloc_obj(*entry);
94*234895faSYonatan Nachum 	if (!entry) {
95*234895faSYonatan Nachum 		mutex_unlock(&ah_cache->lock);
96*234895faSYonatan Nachum 		return ERR_PTR(-ENOMEM);
97*234895faSYonatan Nachum 	}
98*234895faSYonatan Nachum 
99*234895faSYonatan Nachum 	memcpy(entry->key.gid, gid, sizeof(entry->key.gid));
100*234895faSYonatan Nachum 	entry->key.pd = pd;
101*234895faSYonatan Nachum 	refcount_set(&entry->refcount, 1);
102*234895faSYonatan Nachum 	mutex_init(&entry->lock);
103*234895faSYonatan Nachum 
104*234895faSYonatan Nachum 	err = rhashtable_insert_fast(&ah_cache->hashtable, &entry->linkage, ah_cache_params);
105*234895faSYonatan Nachum 	if (err) {
106*234895faSYonatan Nachum 		mutex_destroy(&entry->lock);
107*234895faSYonatan Nachum 		kfree(entry);
108*234895faSYonatan Nachum 		mutex_unlock(&ah_cache->lock);
109*234895faSYonatan Nachum 		return ERR_PTR(err);
110*234895faSYonatan Nachum 	}
111*234895faSYonatan Nachum 
112*234895faSYonatan Nachum 	mutex_unlock(&ah_cache->lock);
113*234895faSYonatan Nachum 	return entry;
114*234895faSYonatan Nachum }
115*234895faSYonatan Nachum 
116*234895faSYonatan Nachum /**
117*234895faSYonatan Nachum  * efa_ah_cache_put - Put a refcount of an AH cache entry
118*234895faSYonatan Nachum  * @ah_cache: AH cache
119*234895faSYonatan Nachum  * @entry: AH cache entry
120*234895faSYonatan Nachum  *
121*234895faSYonatan Nachum  * Drop the refcount. If it reaches zero, remove the entry from the hashtable
122*234895faSYonatan Nachum  * and free it.
123*234895faSYonatan Nachum  */
124*234895faSYonatan Nachum void efa_ah_cache_put(struct efa_ah_cache *ah_cache, struct efa_ah_cache_entry *entry)
125*234895faSYonatan Nachum {
126*234895faSYonatan Nachum 	if (!refcount_dec_and_mutex_lock(&entry->refcount, &ah_cache->lock))
127*234895faSYonatan Nachum 		return;
128*234895faSYonatan Nachum 
129*234895faSYonatan Nachum 	/* AH cache lock is held here */
130*234895faSYonatan Nachum 	rhashtable_remove_fast(&ah_cache->hashtable, &entry->linkage, ah_cache_params);
131*234895faSYonatan Nachum 	mutex_unlock(&ah_cache->lock);
132*234895faSYonatan Nachum 
133*234895faSYonatan Nachum 	mutex_destroy(&entry->lock);
134*234895faSYonatan Nachum 	kfree(entry);
135*234895faSYonatan Nachum }
136