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