162306a36Sopenharmony_ci/* 262306a36Sopenharmony_ci * Copyright (c) 2004 Topspin Communications. All rights reserved. 362306a36Sopenharmony_ci * Copyright (c) 2005 Intel Corporation. All rights reserved. 462306a36Sopenharmony_ci * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved. 562306a36Sopenharmony_ci * Copyright (c) 2005 Voltaire, Inc. All rights reserved. 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci * This software is available to you under a choice of one of two 862306a36Sopenharmony_ci * licenses. You may choose to be licensed under the terms of the GNU 962306a36Sopenharmony_ci * General Public License (GPL) Version 2, available from the file 1062306a36Sopenharmony_ci * COPYING in the main directory of this source tree, or the 1162306a36Sopenharmony_ci * OpenIB.org BSD license below: 1262306a36Sopenharmony_ci * 1362306a36Sopenharmony_ci * Redistribution and use in source and binary forms, with or 1462306a36Sopenharmony_ci * without modification, are permitted provided that the following 1562306a36Sopenharmony_ci * conditions are met: 1662306a36Sopenharmony_ci * 1762306a36Sopenharmony_ci * - Redistributions of source code must retain the above 1862306a36Sopenharmony_ci * copyright notice, this list of conditions and the following 1962306a36Sopenharmony_ci * disclaimer. 2062306a36Sopenharmony_ci * 2162306a36Sopenharmony_ci * - Redistributions in binary form must reproduce the above 2262306a36Sopenharmony_ci * copyright notice, this list of conditions and the following 2362306a36Sopenharmony_ci * disclaimer in the documentation and/or other materials 2462306a36Sopenharmony_ci * provided with the distribution. 2562306a36Sopenharmony_ci * 2662306a36Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 2762306a36Sopenharmony_ci * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 2862306a36Sopenharmony_ci * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 2962306a36Sopenharmony_ci * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 3062306a36Sopenharmony_ci * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 3162306a36Sopenharmony_ci * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 3262306a36Sopenharmony_ci * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 3362306a36Sopenharmony_ci * SOFTWARE. 3462306a36Sopenharmony_ci */ 3562306a36Sopenharmony_ci 3662306a36Sopenharmony_ci#include <linux/if_vlan.h> 3762306a36Sopenharmony_ci#include <linux/errno.h> 3862306a36Sopenharmony_ci#include <linux/slab.h> 3962306a36Sopenharmony_ci#include <linux/workqueue.h> 4062306a36Sopenharmony_ci#include <linux/netdevice.h> 4162306a36Sopenharmony_ci#include <net/addrconf.h> 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_ci#include <rdma/ib_cache.h> 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_ci#include "core_priv.h" 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_cistruct ib_pkey_cache { 4862306a36Sopenharmony_ci int table_len; 4962306a36Sopenharmony_ci u16 table[]; 5062306a36Sopenharmony_ci}; 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_cistruct ib_update_work { 5362306a36Sopenharmony_ci struct work_struct work; 5462306a36Sopenharmony_ci struct ib_event event; 5562306a36Sopenharmony_ci bool enforce_security; 5662306a36Sopenharmony_ci}; 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_ciunion ib_gid zgid; 5962306a36Sopenharmony_ciEXPORT_SYMBOL(zgid); 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_cienum gid_attr_find_mask { 6262306a36Sopenharmony_ci GID_ATTR_FIND_MASK_GID = 1UL << 0, 6362306a36Sopenharmony_ci GID_ATTR_FIND_MASK_NETDEV = 1UL << 1, 6462306a36Sopenharmony_ci GID_ATTR_FIND_MASK_DEFAULT = 1UL << 2, 6562306a36Sopenharmony_ci GID_ATTR_FIND_MASK_GID_TYPE = 1UL << 3, 6662306a36Sopenharmony_ci}; 6762306a36Sopenharmony_ci 6862306a36Sopenharmony_cienum gid_table_entry_state { 6962306a36Sopenharmony_ci GID_TABLE_ENTRY_INVALID = 1, 7062306a36Sopenharmony_ci GID_TABLE_ENTRY_VALID = 2, 7162306a36Sopenharmony_ci /* 7262306a36Sopenharmony_ci * Indicates that entry is pending to be removed, there may 7362306a36Sopenharmony_ci * be active users of this GID entry. 7462306a36Sopenharmony_ci * When last user of the GID entry releases reference to it, 7562306a36Sopenharmony_ci * GID entry is detached from the table. 7662306a36Sopenharmony_ci */ 7762306a36Sopenharmony_ci GID_TABLE_ENTRY_PENDING_DEL = 3, 7862306a36Sopenharmony_ci}; 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_cistruct roce_gid_ndev_storage { 8162306a36Sopenharmony_ci struct rcu_head rcu_head; 8262306a36Sopenharmony_ci struct net_device *ndev; 8362306a36Sopenharmony_ci}; 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_cistruct ib_gid_table_entry { 8662306a36Sopenharmony_ci struct kref kref; 8762306a36Sopenharmony_ci struct work_struct del_work; 8862306a36Sopenharmony_ci struct ib_gid_attr attr; 8962306a36Sopenharmony_ci void *context; 9062306a36Sopenharmony_ci /* Store the ndev pointer to release reference later on in 9162306a36Sopenharmony_ci * call_rcu context because by that time gid_table_entry 9262306a36Sopenharmony_ci * and attr might be already freed. So keep a copy of it. 9362306a36Sopenharmony_ci * ndev_storage is freed by rcu callback. 9462306a36Sopenharmony_ci */ 9562306a36Sopenharmony_ci struct roce_gid_ndev_storage *ndev_storage; 9662306a36Sopenharmony_ci enum gid_table_entry_state state; 9762306a36Sopenharmony_ci}; 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_cistruct ib_gid_table { 10062306a36Sopenharmony_ci int sz; 10162306a36Sopenharmony_ci /* In RoCE, adding a GID to the table requires: 10262306a36Sopenharmony_ci * (a) Find if this GID is already exists. 10362306a36Sopenharmony_ci * (b) Find a free space. 10462306a36Sopenharmony_ci * (c) Write the new GID 10562306a36Sopenharmony_ci * 10662306a36Sopenharmony_ci * Delete requires different set of operations: 10762306a36Sopenharmony_ci * (a) Find the GID 10862306a36Sopenharmony_ci * (b) Delete it. 10962306a36Sopenharmony_ci * 11062306a36Sopenharmony_ci **/ 11162306a36Sopenharmony_ci /* Any writer to data_vec must hold this lock and the write side of 11262306a36Sopenharmony_ci * rwlock. Readers must hold only rwlock. All writers must be in a 11362306a36Sopenharmony_ci * sleepable context. 11462306a36Sopenharmony_ci */ 11562306a36Sopenharmony_ci struct mutex lock; 11662306a36Sopenharmony_ci /* rwlock protects data_vec[ix]->state and entry pointer. 11762306a36Sopenharmony_ci */ 11862306a36Sopenharmony_ci rwlock_t rwlock; 11962306a36Sopenharmony_ci struct ib_gid_table_entry **data_vec; 12062306a36Sopenharmony_ci /* bit field, each bit indicates the index of default GID */ 12162306a36Sopenharmony_ci u32 default_gid_indices; 12262306a36Sopenharmony_ci}; 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_cistatic void dispatch_gid_change_event(struct ib_device *ib_dev, u32 port) 12562306a36Sopenharmony_ci{ 12662306a36Sopenharmony_ci struct ib_event event; 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_ci event.device = ib_dev; 12962306a36Sopenharmony_ci event.element.port_num = port; 13062306a36Sopenharmony_ci event.event = IB_EVENT_GID_CHANGE; 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_ci ib_dispatch_event_clients(&event); 13362306a36Sopenharmony_ci} 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_cistatic const char * const gid_type_str[] = { 13662306a36Sopenharmony_ci /* IB/RoCE v1 value is set for IB_GID_TYPE_IB and IB_GID_TYPE_ROCE for 13762306a36Sopenharmony_ci * user space compatibility reasons. 13862306a36Sopenharmony_ci */ 13962306a36Sopenharmony_ci [IB_GID_TYPE_IB] = "IB/RoCE v1", 14062306a36Sopenharmony_ci [IB_GID_TYPE_ROCE] = "IB/RoCE v1", 14162306a36Sopenharmony_ci [IB_GID_TYPE_ROCE_UDP_ENCAP] = "RoCE v2", 14262306a36Sopenharmony_ci}; 14362306a36Sopenharmony_ci 14462306a36Sopenharmony_ciconst char *ib_cache_gid_type_str(enum ib_gid_type gid_type) 14562306a36Sopenharmony_ci{ 14662306a36Sopenharmony_ci if (gid_type < ARRAY_SIZE(gid_type_str) && gid_type_str[gid_type]) 14762306a36Sopenharmony_ci return gid_type_str[gid_type]; 14862306a36Sopenharmony_ci 14962306a36Sopenharmony_ci return "Invalid GID type"; 15062306a36Sopenharmony_ci} 15162306a36Sopenharmony_ciEXPORT_SYMBOL(ib_cache_gid_type_str); 15262306a36Sopenharmony_ci 15362306a36Sopenharmony_ci/** rdma_is_zero_gid - Check if given GID is zero or not. 15462306a36Sopenharmony_ci * @gid: GID to check 15562306a36Sopenharmony_ci * Returns true if given GID is zero, returns false otherwise. 15662306a36Sopenharmony_ci */ 15762306a36Sopenharmony_cibool rdma_is_zero_gid(const union ib_gid *gid) 15862306a36Sopenharmony_ci{ 15962306a36Sopenharmony_ci return !memcmp(gid, &zgid, sizeof(*gid)); 16062306a36Sopenharmony_ci} 16162306a36Sopenharmony_ciEXPORT_SYMBOL(rdma_is_zero_gid); 16262306a36Sopenharmony_ci 16362306a36Sopenharmony_ci/** is_gid_index_default - Check if a given index belongs to 16462306a36Sopenharmony_ci * reserved default GIDs or not. 16562306a36Sopenharmony_ci * @table: GID table pointer 16662306a36Sopenharmony_ci * @index: Index to check in GID table 16762306a36Sopenharmony_ci * Returns true if index is one of the reserved default GID index otherwise 16862306a36Sopenharmony_ci * returns false. 16962306a36Sopenharmony_ci */ 17062306a36Sopenharmony_cistatic bool is_gid_index_default(const struct ib_gid_table *table, 17162306a36Sopenharmony_ci unsigned int index) 17262306a36Sopenharmony_ci{ 17362306a36Sopenharmony_ci return index < 32 && (BIT(index) & table->default_gid_indices); 17462306a36Sopenharmony_ci} 17562306a36Sopenharmony_ci 17662306a36Sopenharmony_ciint ib_cache_gid_parse_type_str(const char *buf) 17762306a36Sopenharmony_ci{ 17862306a36Sopenharmony_ci unsigned int i; 17962306a36Sopenharmony_ci size_t len; 18062306a36Sopenharmony_ci int err = -EINVAL; 18162306a36Sopenharmony_ci 18262306a36Sopenharmony_ci len = strlen(buf); 18362306a36Sopenharmony_ci if (len == 0) 18462306a36Sopenharmony_ci return -EINVAL; 18562306a36Sopenharmony_ci 18662306a36Sopenharmony_ci if (buf[len - 1] == '\n') 18762306a36Sopenharmony_ci len--; 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(gid_type_str); ++i) 19062306a36Sopenharmony_ci if (gid_type_str[i] && !strncmp(buf, gid_type_str[i], len) && 19162306a36Sopenharmony_ci len == strlen(gid_type_str[i])) { 19262306a36Sopenharmony_ci err = i; 19362306a36Sopenharmony_ci break; 19462306a36Sopenharmony_ci } 19562306a36Sopenharmony_ci 19662306a36Sopenharmony_ci return err; 19762306a36Sopenharmony_ci} 19862306a36Sopenharmony_ciEXPORT_SYMBOL(ib_cache_gid_parse_type_str); 19962306a36Sopenharmony_ci 20062306a36Sopenharmony_cistatic struct ib_gid_table *rdma_gid_table(struct ib_device *device, u32 port) 20162306a36Sopenharmony_ci{ 20262306a36Sopenharmony_ci return device->port_data[port].cache.gid; 20362306a36Sopenharmony_ci} 20462306a36Sopenharmony_ci 20562306a36Sopenharmony_cistatic bool is_gid_entry_free(const struct ib_gid_table_entry *entry) 20662306a36Sopenharmony_ci{ 20762306a36Sopenharmony_ci return !entry; 20862306a36Sopenharmony_ci} 20962306a36Sopenharmony_ci 21062306a36Sopenharmony_cistatic bool is_gid_entry_valid(const struct ib_gid_table_entry *entry) 21162306a36Sopenharmony_ci{ 21262306a36Sopenharmony_ci return entry && entry->state == GID_TABLE_ENTRY_VALID; 21362306a36Sopenharmony_ci} 21462306a36Sopenharmony_ci 21562306a36Sopenharmony_cistatic void schedule_free_gid(struct kref *kref) 21662306a36Sopenharmony_ci{ 21762306a36Sopenharmony_ci struct ib_gid_table_entry *entry = 21862306a36Sopenharmony_ci container_of(kref, struct ib_gid_table_entry, kref); 21962306a36Sopenharmony_ci 22062306a36Sopenharmony_ci queue_work(ib_wq, &entry->del_work); 22162306a36Sopenharmony_ci} 22262306a36Sopenharmony_ci 22362306a36Sopenharmony_cistatic void put_gid_ndev(struct rcu_head *head) 22462306a36Sopenharmony_ci{ 22562306a36Sopenharmony_ci struct roce_gid_ndev_storage *storage = 22662306a36Sopenharmony_ci container_of(head, struct roce_gid_ndev_storage, rcu_head); 22762306a36Sopenharmony_ci 22862306a36Sopenharmony_ci WARN_ON(!storage->ndev); 22962306a36Sopenharmony_ci /* At this point its safe to release netdev reference, 23062306a36Sopenharmony_ci * as all callers working on gid_attr->ndev are done 23162306a36Sopenharmony_ci * using this netdev. 23262306a36Sopenharmony_ci */ 23362306a36Sopenharmony_ci dev_put(storage->ndev); 23462306a36Sopenharmony_ci kfree(storage); 23562306a36Sopenharmony_ci} 23662306a36Sopenharmony_ci 23762306a36Sopenharmony_cistatic void free_gid_entry_locked(struct ib_gid_table_entry *entry) 23862306a36Sopenharmony_ci{ 23962306a36Sopenharmony_ci struct ib_device *device = entry->attr.device; 24062306a36Sopenharmony_ci u32 port_num = entry->attr.port_num; 24162306a36Sopenharmony_ci struct ib_gid_table *table = rdma_gid_table(device, port_num); 24262306a36Sopenharmony_ci 24362306a36Sopenharmony_ci dev_dbg(&device->dev, "%s port=%u index=%u gid %pI6\n", __func__, 24462306a36Sopenharmony_ci port_num, entry->attr.index, entry->attr.gid.raw); 24562306a36Sopenharmony_ci 24662306a36Sopenharmony_ci write_lock_irq(&table->rwlock); 24762306a36Sopenharmony_ci 24862306a36Sopenharmony_ci /* 24962306a36Sopenharmony_ci * The only way to avoid overwriting NULL in table is 25062306a36Sopenharmony_ci * by comparing if it is same entry in table or not! 25162306a36Sopenharmony_ci * If new entry in table is added by the time we free here, 25262306a36Sopenharmony_ci * don't overwrite the table entry. 25362306a36Sopenharmony_ci */ 25462306a36Sopenharmony_ci if (entry == table->data_vec[entry->attr.index]) 25562306a36Sopenharmony_ci table->data_vec[entry->attr.index] = NULL; 25662306a36Sopenharmony_ci /* Now this index is ready to be allocated */ 25762306a36Sopenharmony_ci write_unlock_irq(&table->rwlock); 25862306a36Sopenharmony_ci 25962306a36Sopenharmony_ci if (entry->ndev_storage) 26062306a36Sopenharmony_ci call_rcu(&entry->ndev_storage->rcu_head, put_gid_ndev); 26162306a36Sopenharmony_ci kfree(entry); 26262306a36Sopenharmony_ci} 26362306a36Sopenharmony_ci 26462306a36Sopenharmony_cistatic void free_gid_entry(struct kref *kref) 26562306a36Sopenharmony_ci{ 26662306a36Sopenharmony_ci struct ib_gid_table_entry *entry = 26762306a36Sopenharmony_ci container_of(kref, struct ib_gid_table_entry, kref); 26862306a36Sopenharmony_ci 26962306a36Sopenharmony_ci free_gid_entry_locked(entry); 27062306a36Sopenharmony_ci} 27162306a36Sopenharmony_ci 27262306a36Sopenharmony_ci/** 27362306a36Sopenharmony_ci * free_gid_work - Release reference to the GID entry 27462306a36Sopenharmony_ci * @work: Work structure to refer to GID entry which needs to be 27562306a36Sopenharmony_ci * deleted. 27662306a36Sopenharmony_ci * 27762306a36Sopenharmony_ci * free_gid_work() frees the entry from the HCA's hardware table 27862306a36Sopenharmony_ci * if provider supports it. It releases reference to netdevice. 27962306a36Sopenharmony_ci */ 28062306a36Sopenharmony_cistatic void free_gid_work(struct work_struct *work) 28162306a36Sopenharmony_ci{ 28262306a36Sopenharmony_ci struct ib_gid_table_entry *entry = 28362306a36Sopenharmony_ci container_of(work, struct ib_gid_table_entry, del_work); 28462306a36Sopenharmony_ci struct ib_device *device = entry->attr.device; 28562306a36Sopenharmony_ci u32 port_num = entry->attr.port_num; 28662306a36Sopenharmony_ci struct ib_gid_table *table = rdma_gid_table(device, port_num); 28762306a36Sopenharmony_ci 28862306a36Sopenharmony_ci mutex_lock(&table->lock); 28962306a36Sopenharmony_ci free_gid_entry_locked(entry); 29062306a36Sopenharmony_ci mutex_unlock(&table->lock); 29162306a36Sopenharmony_ci} 29262306a36Sopenharmony_ci 29362306a36Sopenharmony_cistatic struct ib_gid_table_entry * 29462306a36Sopenharmony_cialloc_gid_entry(const struct ib_gid_attr *attr) 29562306a36Sopenharmony_ci{ 29662306a36Sopenharmony_ci struct ib_gid_table_entry *entry; 29762306a36Sopenharmony_ci struct net_device *ndev; 29862306a36Sopenharmony_ci 29962306a36Sopenharmony_ci entry = kzalloc(sizeof(*entry), GFP_KERNEL); 30062306a36Sopenharmony_ci if (!entry) 30162306a36Sopenharmony_ci return NULL; 30262306a36Sopenharmony_ci 30362306a36Sopenharmony_ci ndev = rcu_dereference_protected(attr->ndev, 1); 30462306a36Sopenharmony_ci if (ndev) { 30562306a36Sopenharmony_ci entry->ndev_storage = kzalloc(sizeof(*entry->ndev_storage), 30662306a36Sopenharmony_ci GFP_KERNEL); 30762306a36Sopenharmony_ci if (!entry->ndev_storage) { 30862306a36Sopenharmony_ci kfree(entry); 30962306a36Sopenharmony_ci return NULL; 31062306a36Sopenharmony_ci } 31162306a36Sopenharmony_ci dev_hold(ndev); 31262306a36Sopenharmony_ci entry->ndev_storage->ndev = ndev; 31362306a36Sopenharmony_ci } 31462306a36Sopenharmony_ci kref_init(&entry->kref); 31562306a36Sopenharmony_ci memcpy(&entry->attr, attr, sizeof(*attr)); 31662306a36Sopenharmony_ci INIT_WORK(&entry->del_work, free_gid_work); 31762306a36Sopenharmony_ci entry->state = GID_TABLE_ENTRY_INVALID; 31862306a36Sopenharmony_ci return entry; 31962306a36Sopenharmony_ci} 32062306a36Sopenharmony_ci 32162306a36Sopenharmony_cistatic void store_gid_entry(struct ib_gid_table *table, 32262306a36Sopenharmony_ci struct ib_gid_table_entry *entry) 32362306a36Sopenharmony_ci{ 32462306a36Sopenharmony_ci entry->state = GID_TABLE_ENTRY_VALID; 32562306a36Sopenharmony_ci 32662306a36Sopenharmony_ci dev_dbg(&entry->attr.device->dev, "%s port=%u index=%u gid %pI6\n", 32762306a36Sopenharmony_ci __func__, entry->attr.port_num, entry->attr.index, 32862306a36Sopenharmony_ci entry->attr.gid.raw); 32962306a36Sopenharmony_ci 33062306a36Sopenharmony_ci lockdep_assert_held(&table->lock); 33162306a36Sopenharmony_ci write_lock_irq(&table->rwlock); 33262306a36Sopenharmony_ci table->data_vec[entry->attr.index] = entry; 33362306a36Sopenharmony_ci write_unlock_irq(&table->rwlock); 33462306a36Sopenharmony_ci} 33562306a36Sopenharmony_ci 33662306a36Sopenharmony_cistatic void get_gid_entry(struct ib_gid_table_entry *entry) 33762306a36Sopenharmony_ci{ 33862306a36Sopenharmony_ci kref_get(&entry->kref); 33962306a36Sopenharmony_ci} 34062306a36Sopenharmony_ci 34162306a36Sopenharmony_cistatic void put_gid_entry(struct ib_gid_table_entry *entry) 34262306a36Sopenharmony_ci{ 34362306a36Sopenharmony_ci kref_put(&entry->kref, schedule_free_gid); 34462306a36Sopenharmony_ci} 34562306a36Sopenharmony_ci 34662306a36Sopenharmony_cistatic void put_gid_entry_locked(struct ib_gid_table_entry *entry) 34762306a36Sopenharmony_ci{ 34862306a36Sopenharmony_ci kref_put(&entry->kref, free_gid_entry); 34962306a36Sopenharmony_ci} 35062306a36Sopenharmony_ci 35162306a36Sopenharmony_cistatic int add_roce_gid(struct ib_gid_table_entry *entry) 35262306a36Sopenharmony_ci{ 35362306a36Sopenharmony_ci const struct ib_gid_attr *attr = &entry->attr; 35462306a36Sopenharmony_ci int ret; 35562306a36Sopenharmony_ci 35662306a36Sopenharmony_ci if (!attr->ndev) { 35762306a36Sopenharmony_ci dev_err(&attr->device->dev, "%s NULL netdev port=%u index=%u\n", 35862306a36Sopenharmony_ci __func__, attr->port_num, attr->index); 35962306a36Sopenharmony_ci return -EINVAL; 36062306a36Sopenharmony_ci } 36162306a36Sopenharmony_ci if (rdma_cap_roce_gid_table(attr->device, attr->port_num)) { 36262306a36Sopenharmony_ci ret = attr->device->ops.add_gid(attr, &entry->context); 36362306a36Sopenharmony_ci if (ret) { 36462306a36Sopenharmony_ci dev_err(&attr->device->dev, 36562306a36Sopenharmony_ci "%s GID add failed port=%u index=%u\n", 36662306a36Sopenharmony_ci __func__, attr->port_num, attr->index); 36762306a36Sopenharmony_ci return ret; 36862306a36Sopenharmony_ci } 36962306a36Sopenharmony_ci } 37062306a36Sopenharmony_ci return 0; 37162306a36Sopenharmony_ci} 37262306a36Sopenharmony_ci 37362306a36Sopenharmony_ci/** 37462306a36Sopenharmony_ci * del_gid - Delete GID table entry 37562306a36Sopenharmony_ci * 37662306a36Sopenharmony_ci * @ib_dev: IB device whose GID entry to be deleted 37762306a36Sopenharmony_ci * @port: Port number of the IB device 37862306a36Sopenharmony_ci * @table: GID table of the IB device for a port 37962306a36Sopenharmony_ci * @ix: GID entry index to delete 38062306a36Sopenharmony_ci * 38162306a36Sopenharmony_ci */ 38262306a36Sopenharmony_cistatic void del_gid(struct ib_device *ib_dev, u32 port, 38362306a36Sopenharmony_ci struct ib_gid_table *table, int ix) 38462306a36Sopenharmony_ci{ 38562306a36Sopenharmony_ci struct roce_gid_ndev_storage *ndev_storage; 38662306a36Sopenharmony_ci struct ib_gid_table_entry *entry; 38762306a36Sopenharmony_ci 38862306a36Sopenharmony_ci lockdep_assert_held(&table->lock); 38962306a36Sopenharmony_ci 39062306a36Sopenharmony_ci dev_dbg(&ib_dev->dev, "%s port=%u index=%d gid %pI6\n", __func__, port, 39162306a36Sopenharmony_ci ix, table->data_vec[ix]->attr.gid.raw); 39262306a36Sopenharmony_ci 39362306a36Sopenharmony_ci write_lock_irq(&table->rwlock); 39462306a36Sopenharmony_ci entry = table->data_vec[ix]; 39562306a36Sopenharmony_ci entry->state = GID_TABLE_ENTRY_PENDING_DEL; 39662306a36Sopenharmony_ci /* 39762306a36Sopenharmony_ci * For non RoCE protocol, GID entry slot is ready to use. 39862306a36Sopenharmony_ci */ 39962306a36Sopenharmony_ci if (!rdma_protocol_roce(ib_dev, port)) 40062306a36Sopenharmony_ci table->data_vec[ix] = NULL; 40162306a36Sopenharmony_ci write_unlock_irq(&table->rwlock); 40262306a36Sopenharmony_ci 40362306a36Sopenharmony_ci if (rdma_cap_roce_gid_table(ib_dev, port)) 40462306a36Sopenharmony_ci ib_dev->ops.del_gid(&entry->attr, &entry->context); 40562306a36Sopenharmony_ci 40662306a36Sopenharmony_ci ndev_storage = entry->ndev_storage; 40762306a36Sopenharmony_ci if (ndev_storage) { 40862306a36Sopenharmony_ci entry->ndev_storage = NULL; 40962306a36Sopenharmony_ci rcu_assign_pointer(entry->attr.ndev, NULL); 41062306a36Sopenharmony_ci call_rcu(&ndev_storage->rcu_head, put_gid_ndev); 41162306a36Sopenharmony_ci } 41262306a36Sopenharmony_ci 41362306a36Sopenharmony_ci put_gid_entry_locked(entry); 41462306a36Sopenharmony_ci} 41562306a36Sopenharmony_ci 41662306a36Sopenharmony_ci/** 41762306a36Sopenharmony_ci * add_modify_gid - Add or modify GID table entry 41862306a36Sopenharmony_ci * 41962306a36Sopenharmony_ci * @table: GID table in which GID to be added or modified 42062306a36Sopenharmony_ci * @attr: Attributes of the GID 42162306a36Sopenharmony_ci * 42262306a36Sopenharmony_ci * Returns 0 on success or appropriate error code. It accepts zero 42362306a36Sopenharmony_ci * GID addition for non RoCE ports for HCA's who report them as valid 42462306a36Sopenharmony_ci * GID. However such zero GIDs are not added to the cache. 42562306a36Sopenharmony_ci */ 42662306a36Sopenharmony_cistatic int add_modify_gid(struct ib_gid_table *table, 42762306a36Sopenharmony_ci const struct ib_gid_attr *attr) 42862306a36Sopenharmony_ci{ 42962306a36Sopenharmony_ci struct ib_gid_table_entry *entry; 43062306a36Sopenharmony_ci int ret = 0; 43162306a36Sopenharmony_ci 43262306a36Sopenharmony_ci /* 43362306a36Sopenharmony_ci * Invalidate any old entry in the table to make it safe to write to 43462306a36Sopenharmony_ci * this index. 43562306a36Sopenharmony_ci */ 43662306a36Sopenharmony_ci if (is_gid_entry_valid(table->data_vec[attr->index])) 43762306a36Sopenharmony_ci del_gid(attr->device, attr->port_num, table, attr->index); 43862306a36Sopenharmony_ci 43962306a36Sopenharmony_ci /* 44062306a36Sopenharmony_ci * Some HCA's report multiple GID entries with only one valid GID, and 44162306a36Sopenharmony_ci * leave other unused entries as the zero GID. Convert zero GIDs to 44262306a36Sopenharmony_ci * empty table entries instead of storing them. 44362306a36Sopenharmony_ci */ 44462306a36Sopenharmony_ci if (rdma_is_zero_gid(&attr->gid)) 44562306a36Sopenharmony_ci return 0; 44662306a36Sopenharmony_ci 44762306a36Sopenharmony_ci entry = alloc_gid_entry(attr); 44862306a36Sopenharmony_ci if (!entry) 44962306a36Sopenharmony_ci return -ENOMEM; 45062306a36Sopenharmony_ci 45162306a36Sopenharmony_ci if (rdma_protocol_roce(attr->device, attr->port_num)) { 45262306a36Sopenharmony_ci ret = add_roce_gid(entry); 45362306a36Sopenharmony_ci if (ret) 45462306a36Sopenharmony_ci goto done; 45562306a36Sopenharmony_ci } 45662306a36Sopenharmony_ci 45762306a36Sopenharmony_ci store_gid_entry(table, entry); 45862306a36Sopenharmony_ci return 0; 45962306a36Sopenharmony_ci 46062306a36Sopenharmony_cidone: 46162306a36Sopenharmony_ci put_gid_entry(entry); 46262306a36Sopenharmony_ci return ret; 46362306a36Sopenharmony_ci} 46462306a36Sopenharmony_ci 46562306a36Sopenharmony_ci/* rwlock should be read locked, or lock should be held */ 46662306a36Sopenharmony_cistatic int find_gid(struct ib_gid_table *table, const union ib_gid *gid, 46762306a36Sopenharmony_ci const struct ib_gid_attr *val, bool default_gid, 46862306a36Sopenharmony_ci unsigned long mask, int *pempty) 46962306a36Sopenharmony_ci{ 47062306a36Sopenharmony_ci int i = 0; 47162306a36Sopenharmony_ci int found = -1; 47262306a36Sopenharmony_ci int empty = pempty ? -1 : 0; 47362306a36Sopenharmony_ci 47462306a36Sopenharmony_ci while (i < table->sz && (found < 0 || empty < 0)) { 47562306a36Sopenharmony_ci struct ib_gid_table_entry *data = table->data_vec[i]; 47662306a36Sopenharmony_ci struct ib_gid_attr *attr; 47762306a36Sopenharmony_ci int curr_index = i; 47862306a36Sopenharmony_ci 47962306a36Sopenharmony_ci i++; 48062306a36Sopenharmony_ci 48162306a36Sopenharmony_ci /* find_gid() is used during GID addition where it is expected 48262306a36Sopenharmony_ci * to return a free entry slot which is not duplicate. 48362306a36Sopenharmony_ci * Free entry slot is requested and returned if pempty is set, 48462306a36Sopenharmony_ci * so lookup free slot only if requested. 48562306a36Sopenharmony_ci */ 48662306a36Sopenharmony_ci if (pempty && empty < 0) { 48762306a36Sopenharmony_ci if (is_gid_entry_free(data) && 48862306a36Sopenharmony_ci default_gid == 48962306a36Sopenharmony_ci is_gid_index_default(table, curr_index)) { 49062306a36Sopenharmony_ci /* 49162306a36Sopenharmony_ci * Found an invalid (free) entry; allocate it. 49262306a36Sopenharmony_ci * If default GID is requested, then our 49362306a36Sopenharmony_ci * found slot must be one of the DEFAULT 49462306a36Sopenharmony_ci * reserved slots or we fail. 49562306a36Sopenharmony_ci * This ensures that only DEFAULT reserved 49662306a36Sopenharmony_ci * slots are used for default property GIDs. 49762306a36Sopenharmony_ci */ 49862306a36Sopenharmony_ci empty = curr_index; 49962306a36Sopenharmony_ci } 50062306a36Sopenharmony_ci } 50162306a36Sopenharmony_ci 50262306a36Sopenharmony_ci /* 50362306a36Sopenharmony_ci * Additionally find_gid() is used to find valid entry during 50462306a36Sopenharmony_ci * lookup operation; so ignore the entries which are marked as 50562306a36Sopenharmony_ci * pending for removal and the entries which are marked as 50662306a36Sopenharmony_ci * invalid. 50762306a36Sopenharmony_ci */ 50862306a36Sopenharmony_ci if (!is_gid_entry_valid(data)) 50962306a36Sopenharmony_ci continue; 51062306a36Sopenharmony_ci 51162306a36Sopenharmony_ci if (found >= 0) 51262306a36Sopenharmony_ci continue; 51362306a36Sopenharmony_ci 51462306a36Sopenharmony_ci attr = &data->attr; 51562306a36Sopenharmony_ci if (mask & GID_ATTR_FIND_MASK_GID_TYPE && 51662306a36Sopenharmony_ci attr->gid_type != val->gid_type) 51762306a36Sopenharmony_ci continue; 51862306a36Sopenharmony_ci 51962306a36Sopenharmony_ci if (mask & GID_ATTR_FIND_MASK_GID && 52062306a36Sopenharmony_ci memcmp(gid, &data->attr.gid, sizeof(*gid))) 52162306a36Sopenharmony_ci continue; 52262306a36Sopenharmony_ci 52362306a36Sopenharmony_ci if (mask & GID_ATTR_FIND_MASK_NETDEV && 52462306a36Sopenharmony_ci attr->ndev != val->ndev) 52562306a36Sopenharmony_ci continue; 52662306a36Sopenharmony_ci 52762306a36Sopenharmony_ci if (mask & GID_ATTR_FIND_MASK_DEFAULT && 52862306a36Sopenharmony_ci is_gid_index_default(table, curr_index) != default_gid) 52962306a36Sopenharmony_ci continue; 53062306a36Sopenharmony_ci 53162306a36Sopenharmony_ci found = curr_index; 53262306a36Sopenharmony_ci } 53362306a36Sopenharmony_ci 53462306a36Sopenharmony_ci if (pempty) 53562306a36Sopenharmony_ci *pempty = empty; 53662306a36Sopenharmony_ci 53762306a36Sopenharmony_ci return found; 53862306a36Sopenharmony_ci} 53962306a36Sopenharmony_ci 54062306a36Sopenharmony_cistatic void make_default_gid(struct net_device *dev, union ib_gid *gid) 54162306a36Sopenharmony_ci{ 54262306a36Sopenharmony_ci gid->global.subnet_prefix = cpu_to_be64(0xfe80000000000000LL); 54362306a36Sopenharmony_ci addrconf_ifid_eui48(&gid->raw[8], dev); 54462306a36Sopenharmony_ci} 54562306a36Sopenharmony_ci 54662306a36Sopenharmony_cistatic int __ib_cache_gid_add(struct ib_device *ib_dev, u32 port, 54762306a36Sopenharmony_ci union ib_gid *gid, struct ib_gid_attr *attr, 54862306a36Sopenharmony_ci unsigned long mask, bool default_gid) 54962306a36Sopenharmony_ci{ 55062306a36Sopenharmony_ci struct ib_gid_table *table; 55162306a36Sopenharmony_ci int ret = 0; 55262306a36Sopenharmony_ci int empty; 55362306a36Sopenharmony_ci int ix; 55462306a36Sopenharmony_ci 55562306a36Sopenharmony_ci /* Do not allow adding zero GID in support of 55662306a36Sopenharmony_ci * IB spec version 1.3 section 4.1.1 point (6) and 55762306a36Sopenharmony_ci * section 12.7.10 and section 12.7.20 55862306a36Sopenharmony_ci */ 55962306a36Sopenharmony_ci if (rdma_is_zero_gid(gid)) 56062306a36Sopenharmony_ci return -EINVAL; 56162306a36Sopenharmony_ci 56262306a36Sopenharmony_ci table = rdma_gid_table(ib_dev, port); 56362306a36Sopenharmony_ci 56462306a36Sopenharmony_ci mutex_lock(&table->lock); 56562306a36Sopenharmony_ci 56662306a36Sopenharmony_ci ix = find_gid(table, gid, attr, default_gid, mask, &empty); 56762306a36Sopenharmony_ci if (ix >= 0) 56862306a36Sopenharmony_ci goto out_unlock; 56962306a36Sopenharmony_ci 57062306a36Sopenharmony_ci if (empty < 0) { 57162306a36Sopenharmony_ci ret = -ENOSPC; 57262306a36Sopenharmony_ci goto out_unlock; 57362306a36Sopenharmony_ci } 57462306a36Sopenharmony_ci attr->device = ib_dev; 57562306a36Sopenharmony_ci attr->index = empty; 57662306a36Sopenharmony_ci attr->port_num = port; 57762306a36Sopenharmony_ci attr->gid = *gid; 57862306a36Sopenharmony_ci ret = add_modify_gid(table, attr); 57962306a36Sopenharmony_ci if (!ret) 58062306a36Sopenharmony_ci dispatch_gid_change_event(ib_dev, port); 58162306a36Sopenharmony_ci 58262306a36Sopenharmony_ciout_unlock: 58362306a36Sopenharmony_ci mutex_unlock(&table->lock); 58462306a36Sopenharmony_ci if (ret) 58562306a36Sopenharmony_ci pr_warn("%s: unable to add gid %pI6 error=%d\n", 58662306a36Sopenharmony_ci __func__, gid->raw, ret); 58762306a36Sopenharmony_ci return ret; 58862306a36Sopenharmony_ci} 58962306a36Sopenharmony_ci 59062306a36Sopenharmony_ciint ib_cache_gid_add(struct ib_device *ib_dev, u32 port, 59162306a36Sopenharmony_ci union ib_gid *gid, struct ib_gid_attr *attr) 59262306a36Sopenharmony_ci{ 59362306a36Sopenharmony_ci unsigned long mask = GID_ATTR_FIND_MASK_GID | 59462306a36Sopenharmony_ci GID_ATTR_FIND_MASK_GID_TYPE | 59562306a36Sopenharmony_ci GID_ATTR_FIND_MASK_NETDEV; 59662306a36Sopenharmony_ci 59762306a36Sopenharmony_ci return __ib_cache_gid_add(ib_dev, port, gid, attr, mask, false); 59862306a36Sopenharmony_ci} 59962306a36Sopenharmony_ci 60062306a36Sopenharmony_cistatic int 60162306a36Sopenharmony_ci_ib_cache_gid_del(struct ib_device *ib_dev, u32 port, 60262306a36Sopenharmony_ci union ib_gid *gid, struct ib_gid_attr *attr, 60362306a36Sopenharmony_ci unsigned long mask, bool default_gid) 60462306a36Sopenharmony_ci{ 60562306a36Sopenharmony_ci struct ib_gid_table *table; 60662306a36Sopenharmony_ci int ret = 0; 60762306a36Sopenharmony_ci int ix; 60862306a36Sopenharmony_ci 60962306a36Sopenharmony_ci table = rdma_gid_table(ib_dev, port); 61062306a36Sopenharmony_ci 61162306a36Sopenharmony_ci mutex_lock(&table->lock); 61262306a36Sopenharmony_ci 61362306a36Sopenharmony_ci ix = find_gid(table, gid, attr, default_gid, mask, NULL); 61462306a36Sopenharmony_ci if (ix < 0) { 61562306a36Sopenharmony_ci ret = -EINVAL; 61662306a36Sopenharmony_ci goto out_unlock; 61762306a36Sopenharmony_ci } 61862306a36Sopenharmony_ci 61962306a36Sopenharmony_ci del_gid(ib_dev, port, table, ix); 62062306a36Sopenharmony_ci dispatch_gid_change_event(ib_dev, port); 62162306a36Sopenharmony_ci 62262306a36Sopenharmony_ciout_unlock: 62362306a36Sopenharmony_ci mutex_unlock(&table->lock); 62462306a36Sopenharmony_ci if (ret) 62562306a36Sopenharmony_ci pr_debug("%s: can't delete gid %pI6 error=%d\n", 62662306a36Sopenharmony_ci __func__, gid->raw, ret); 62762306a36Sopenharmony_ci return ret; 62862306a36Sopenharmony_ci} 62962306a36Sopenharmony_ci 63062306a36Sopenharmony_ciint ib_cache_gid_del(struct ib_device *ib_dev, u32 port, 63162306a36Sopenharmony_ci union ib_gid *gid, struct ib_gid_attr *attr) 63262306a36Sopenharmony_ci{ 63362306a36Sopenharmony_ci unsigned long mask = GID_ATTR_FIND_MASK_GID | 63462306a36Sopenharmony_ci GID_ATTR_FIND_MASK_GID_TYPE | 63562306a36Sopenharmony_ci GID_ATTR_FIND_MASK_DEFAULT | 63662306a36Sopenharmony_ci GID_ATTR_FIND_MASK_NETDEV; 63762306a36Sopenharmony_ci 63862306a36Sopenharmony_ci return _ib_cache_gid_del(ib_dev, port, gid, attr, mask, false); 63962306a36Sopenharmony_ci} 64062306a36Sopenharmony_ci 64162306a36Sopenharmony_ciint ib_cache_gid_del_all_netdev_gids(struct ib_device *ib_dev, u32 port, 64262306a36Sopenharmony_ci struct net_device *ndev) 64362306a36Sopenharmony_ci{ 64462306a36Sopenharmony_ci struct ib_gid_table *table; 64562306a36Sopenharmony_ci int ix; 64662306a36Sopenharmony_ci bool deleted = false; 64762306a36Sopenharmony_ci 64862306a36Sopenharmony_ci table = rdma_gid_table(ib_dev, port); 64962306a36Sopenharmony_ci 65062306a36Sopenharmony_ci mutex_lock(&table->lock); 65162306a36Sopenharmony_ci 65262306a36Sopenharmony_ci for (ix = 0; ix < table->sz; ix++) { 65362306a36Sopenharmony_ci if (is_gid_entry_valid(table->data_vec[ix]) && 65462306a36Sopenharmony_ci table->data_vec[ix]->attr.ndev == ndev) { 65562306a36Sopenharmony_ci del_gid(ib_dev, port, table, ix); 65662306a36Sopenharmony_ci deleted = true; 65762306a36Sopenharmony_ci } 65862306a36Sopenharmony_ci } 65962306a36Sopenharmony_ci 66062306a36Sopenharmony_ci mutex_unlock(&table->lock); 66162306a36Sopenharmony_ci 66262306a36Sopenharmony_ci if (deleted) 66362306a36Sopenharmony_ci dispatch_gid_change_event(ib_dev, port); 66462306a36Sopenharmony_ci 66562306a36Sopenharmony_ci return 0; 66662306a36Sopenharmony_ci} 66762306a36Sopenharmony_ci 66862306a36Sopenharmony_ci/** 66962306a36Sopenharmony_ci * rdma_find_gid_by_port - Returns the GID entry attributes when it finds 67062306a36Sopenharmony_ci * a valid GID entry for given search parameters. It searches for the specified 67162306a36Sopenharmony_ci * GID value in the local software cache. 67262306a36Sopenharmony_ci * @ib_dev: The device to query. 67362306a36Sopenharmony_ci * @gid: The GID value to search for. 67462306a36Sopenharmony_ci * @gid_type: The GID type to search for. 67562306a36Sopenharmony_ci * @port: The port number of the device where the GID value should be searched. 67662306a36Sopenharmony_ci * @ndev: In RoCE, the net device of the device. NULL means ignore. 67762306a36Sopenharmony_ci * 67862306a36Sopenharmony_ci * Returns sgid attributes if the GID is found with valid reference or 67962306a36Sopenharmony_ci * returns ERR_PTR for the error. 68062306a36Sopenharmony_ci * The caller must invoke rdma_put_gid_attr() to release the reference. 68162306a36Sopenharmony_ci */ 68262306a36Sopenharmony_ciconst struct ib_gid_attr * 68362306a36Sopenharmony_cirdma_find_gid_by_port(struct ib_device *ib_dev, 68462306a36Sopenharmony_ci const union ib_gid *gid, 68562306a36Sopenharmony_ci enum ib_gid_type gid_type, 68662306a36Sopenharmony_ci u32 port, struct net_device *ndev) 68762306a36Sopenharmony_ci{ 68862306a36Sopenharmony_ci int local_index; 68962306a36Sopenharmony_ci struct ib_gid_table *table; 69062306a36Sopenharmony_ci unsigned long mask = GID_ATTR_FIND_MASK_GID | 69162306a36Sopenharmony_ci GID_ATTR_FIND_MASK_GID_TYPE; 69262306a36Sopenharmony_ci struct ib_gid_attr val = {.ndev = ndev, .gid_type = gid_type}; 69362306a36Sopenharmony_ci const struct ib_gid_attr *attr; 69462306a36Sopenharmony_ci unsigned long flags; 69562306a36Sopenharmony_ci 69662306a36Sopenharmony_ci if (!rdma_is_port_valid(ib_dev, port)) 69762306a36Sopenharmony_ci return ERR_PTR(-ENOENT); 69862306a36Sopenharmony_ci 69962306a36Sopenharmony_ci table = rdma_gid_table(ib_dev, port); 70062306a36Sopenharmony_ci 70162306a36Sopenharmony_ci if (ndev) 70262306a36Sopenharmony_ci mask |= GID_ATTR_FIND_MASK_NETDEV; 70362306a36Sopenharmony_ci 70462306a36Sopenharmony_ci read_lock_irqsave(&table->rwlock, flags); 70562306a36Sopenharmony_ci local_index = find_gid(table, gid, &val, false, mask, NULL); 70662306a36Sopenharmony_ci if (local_index >= 0) { 70762306a36Sopenharmony_ci get_gid_entry(table->data_vec[local_index]); 70862306a36Sopenharmony_ci attr = &table->data_vec[local_index]->attr; 70962306a36Sopenharmony_ci read_unlock_irqrestore(&table->rwlock, flags); 71062306a36Sopenharmony_ci return attr; 71162306a36Sopenharmony_ci } 71262306a36Sopenharmony_ci 71362306a36Sopenharmony_ci read_unlock_irqrestore(&table->rwlock, flags); 71462306a36Sopenharmony_ci return ERR_PTR(-ENOENT); 71562306a36Sopenharmony_ci} 71662306a36Sopenharmony_ciEXPORT_SYMBOL(rdma_find_gid_by_port); 71762306a36Sopenharmony_ci 71862306a36Sopenharmony_ci/** 71962306a36Sopenharmony_ci * rdma_find_gid_by_filter - Returns the GID table attribute where a 72062306a36Sopenharmony_ci * specified GID value occurs 72162306a36Sopenharmony_ci * @ib_dev: The device to query. 72262306a36Sopenharmony_ci * @gid: The GID value to search for. 72362306a36Sopenharmony_ci * @port: The port number of the device where the GID value could be 72462306a36Sopenharmony_ci * searched. 72562306a36Sopenharmony_ci * @filter: The filter function is executed on any matching GID in the table. 72662306a36Sopenharmony_ci * If the filter function returns true, the corresponding index is returned, 72762306a36Sopenharmony_ci * otherwise, we continue searching the GID table. It's guaranteed that 72862306a36Sopenharmony_ci * while filter is executed, ndev field is valid and the structure won't 72962306a36Sopenharmony_ci * change. filter is executed in an atomic context. filter must not be NULL. 73062306a36Sopenharmony_ci * @context: Private data to pass into the call-back. 73162306a36Sopenharmony_ci * 73262306a36Sopenharmony_ci * rdma_find_gid_by_filter() searches for the specified GID value 73362306a36Sopenharmony_ci * of which the filter function returns true in the port's GID table. 73462306a36Sopenharmony_ci * 73562306a36Sopenharmony_ci */ 73662306a36Sopenharmony_ciconst struct ib_gid_attr *rdma_find_gid_by_filter( 73762306a36Sopenharmony_ci struct ib_device *ib_dev, const union ib_gid *gid, u32 port, 73862306a36Sopenharmony_ci bool (*filter)(const union ib_gid *gid, const struct ib_gid_attr *, 73962306a36Sopenharmony_ci void *), 74062306a36Sopenharmony_ci void *context) 74162306a36Sopenharmony_ci{ 74262306a36Sopenharmony_ci const struct ib_gid_attr *res = ERR_PTR(-ENOENT); 74362306a36Sopenharmony_ci struct ib_gid_table *table; 74462306a36Sopenharmony_ci unsigned long flags; 74562306a36Sopenharmony_ci unsigned int i; 74662306a36Sopenharmony_ci 74762306a36Sopenharmony_ci if (!rdma_is_port_valid(ib_dev, port)) 74862306a36Sopenharmony_ci return ERR_PTR(-EINVAL); 74962306a36Sopenharmony_ci 75062306a36Sopenharmony_ci table = rdma_gid_table(ib_dev, port); 75162306a36Sopenharmony_ci 75262306a36Sopenharmony_ci read_lock_irqsave(&table->rwlock, flags); 75362306a36Sopenharmony_ci for (i = 0; i < table->sz; i++) { 75462306a36Sopenharmony_ci struct ib_gid_table_entry *entry = table->data_vec[i]; 75562306a36Sopenharmony_ci 75662306a36Sopenharmony_ci if (!is_gid_entry_valid(entry)) 75762306a36Sopenharmony_ci continue; 75862306a36Sopenharmony_ci 75962306a36Sopenharmony_ci if (memcmp(gid, &entry->attr.gid, sizeof(*gid))) 76062306a36Sopenharmony_ci continue; 76162306a36Sopenharmony_ci 76262306a36Sopenharmony_ci if (filter(gid, &entry->attr, context)) { 76362306a36Sopenharmony_ci get_gid_entry(entry); 76462306a36Sopenharmony_ci res = &entry->attr; 76562306a36Sopenharmony_ci break; 76662306a36Sopenharmony_ci } 76762306a36Sopenharmony_ci } 76862306a36Sopenharmony_ci read_unlock_irqrestore(&table->rwlock, flags); 76962306a36Sopenharmony_ci return res; 77062306a36Sopenharmony_ci} 77162306a36Sopenharmony_ci 77262306a36Sopenharmony_cistatic struct ib_gid_table *alloc_gid_table(int sz) 77362306a36Sopenharmony_ci{ 77462306a36Sopenharmony_ci struct ib_gid_table *table = kzalloc(sizeof(*table), GFP_KERNEL); 77562306a36Sopenharmony_ci 77662306a36Sopenharmony_ci if (!table) 77762306a36Sopenharmony_ci return NULL; 77862306a36Sopenharmony_ci 77962306a36Sopenharmony_ci table->data_vec = kcalloc(sz, sizeof(*table->data_vec), GFP_KERNEL); 78062306a36Sopenharmony_ci if (!table->data_vec) 78162306a36Sopenharmony_ci goto err_free_table; 78262306a36Sopenharmony_ci 78362306a36Sopenharmony_ci mutex_init(&table->lock); 78462306a36Sopenharmony_ci 78562306a36Sopenharmony_ci table->sz = sz; 78662306a36Sopenharmony_ci rwlock_init(&table->rwlock); 78762306a36Sopenharmony_ci return table; 78862306a36Sopenharmony_ci 78962306a36Sopenharmony_cierr_free_table: 79062306a36Sopenharmony_ci kfree(table); 79162306a36Sopenharmony_ci return NULL; 79262306a36Sopenharmony_ci} 79362306a36Sopenharmony_ci 79462306a36Sopenharmony_cistatic void release_gid_table(struct ib_device *device, 79562306a36Sopenharmony_ci struct ib_gid_table *table) 79662306a36Sopenharmony_ci{ 79762306a36Sopenharmony_ci bool leak = false; 79862306a36Sopenharmony_ci int i; 79962306a36Sopenharmony_ci 80062306a36Sopenharmony_ci if (!table) 80162306a36Sopenharmony_ci return; 80262306a36Sopenharmony_ci 80362306a36Sopenharmony_ci for (i = 0; i < table->sz; i++) { 80462306a36Sopenharmony_ci if (is_gid_entry_free(table->data_vec[i])) 80562306a36Sopenharmony_ci continue; 80662306a36Sopenharmony_ci if (kref_read(&table->data_vec[i]->kref) > 1) { 80762306a36Sopenharmony_ci dev_err(&device->dev, 80862306a36Sopenharmony_ci "GID entry ref leak for index %d ref=%u\n", i, 80962306a36Sopenharmony_ci kref_read(&table->data_vec[i]->kref)); 81062306a36Sopenharmony_ci leak = true; 81162306a36Sopenharmony_ci } 81262306a36Sopenharmony_ci } 81362306a36Sopenharmony_ci if (leak) 81462306a36Sopenharmony_ci return; 81562306a36Sopenharmony_ci 81662306a36Sopenharmony_ci mutex_destroy(&table->lock); 81762306a36Sopenharmony_ci kfree(table->data_vec); 81862306a36Sopenharmony_ci kfree(table); 81962306a36Sopenharmony_ci} 82062306a36Sopenharmony_ci 82162306a36Sopenharmony_cistatic void cleanup_gid_table_port(struct ib_device *ib_dev, u32 port, 82262306a36Sopenharmony_ci struct ib_gid_table *table) 82362306a36Sopenharmony_ci{ 82462306a36Sopenharmony_ci int i; 82562306a36Sopenharmony_ci 82662306a36Sopenharmony_ci if (!table) 82762306a36Sopenharmony_ci return; 82862306a36Sopenharmony_ci 82962306a36Sopenharmony_ci mutex_lock(&table->lock); 83062306a36Sopenharmony_ci for (i = 0; i < table->sz; ++i) { 83162306a36Sopenharmony_ci if (is_gid_entry_valid(table->data_vec[i])) 83262306a36Sopenharmony_ci del_gid(ib_dev, port, table, i); 83362306a36Sopenharmony_ci } 83462306a36Sopenharmony_ci mutex_unlock(&table->lock); 83562306a36Sopenharmony_ci} 83662306a36Sopenharmony_ci 83762306a36Sopenharmony_civoid ib_cache_gid_set_default_gid(struct ib_device *ib_dev, u32 port, 83862306a36Sopenharmony_ci struct net_device *ndev, 83962306a36Sopenharmony_ci unsigned long gid_type_mask, 84062306a36Sopenharmony_ci enum ib_cache_gid_default_mode mode) 84162306a36Sopenharmony_ci{ 84262306a36Sopenharmony_ci union ib_gid gid = { }; 84362306a36Sopenharmony_ci struct ib_gid_attr gid_attr; 84462306a36Sopenharmony_ci unsigned int gid_type; 84562306a36Sopenharmony_ci unsigned long mask; 84662306a36Sopenharmony_ci 84762306a36Sopenharmony_ci mask = GID_ATTR_FIND_MASK_GID_TYPE | 84862306a36Sopenharmony_ci GID_ATTR_FIND_MASK_DEFAULT | 84962306a36Sopenharmony_ci GID_ATTR_FIND_MASK_NETDEV; 85062306a36Sopenharmony_ci memset(&gid_attr, 0, sizeof(gid_attr)); 85162306a36Sopenharmony_ci gid_attr.ndev = ndev; 85262306a36Sopenharmony_ci 85362306a36Sopenharmony_ci for (gid_type = 0; gid_type < IB_GID_TYPE_SIZE; ++gid_type) { 85462306a36Sopenharmony_ci if (1UL << gid_type & ~gid_type_mask) 85562306a36Sopenharmony_ci continue; 85662306a36Sopenharmony_ci 85762306a36Sopenharmony_ci gid_attr.gid_type = gid_type; 85862306a36Sopenharmony_ci 85962306a36Sopenharmony_ci if (mode == IB_CACHE_GID_DEFAULT_MODE_SET) { 86062306a36Sopenharmony_ci make_default_gid(ndev, &gid); 86162306a36Sopenharmony_ci __ib_cache_gid_add(ib_dev, port, &gid, 86262306a36Sopenharmony_ci &gid_attr, mask, true); 86362306a36Sopenharmony_ci } else if (mode == IB_CACHE_GID_DEFAULT_MODE_DELETE) { 86462306a36Sopenharmony_ci _ib_cache_gid_del(ib_dev, port, &gid, 86562306a36Sopenharmony_ci &gid_attr, mask, true); 86662306a36Sopenharmony_ci } 86762306a36Sopenharmony_ci } 86862306a36Sopenharmony_ci} 86962306a36Sopenharmony_ci 87062306a36Sopenharmony_cistatic void gid_table_reserve_default(struct ib_device *ib_dev, u32 port, 87162306a36Sopenharmony_ci struct ib_gid_table *table) 87262306a36Sopenharmony_ci{ 87362306a36Sopenharmony_ci unsigned int i; 87462306a36Sopenharmony_ci unsigned long roce_gid_type_mask; 87562306a36Sopenharmony_ci unsigned int num_default_gids; 87662306a36Sopenharmony_ci 87762306a36Sopenharmony_ci roce_gid_type_mask = roce_gid_type_mask_support(ib_dev, port); 87862306a36Sopenharmony_ci num_default_gids = hweight_long(roce_gid_type_mask); 87962306a36Sopenharmony_ci /* Reserve starting indices for default GIDs */ 88062306a36Sopenharmony_ci for (i = 0; i < num_default_gids && i < table->sz; i++) 88162306a36Sopenharmony_ci table->default_gid_indices |= BIT(i); 88262306a36Sopenharmony_ci} 88362306a36Sopenharmony_ci 88462306a36Sopenharmony_ci 88562306a36Sopenharmony_cistatic void gid_table_release_one(struct ib_device *ib_dev) 88662306a36Sopenharmony_ci{ 88762306a36Sopenharmony_ci u32 p; 88862306a36Sopenharmony_ci 88962306a36Sopenharmony_ci rdma_for_each_port (ib_dev, p) { 89062306a36Sopenharmony_ci release_gid_table(ib_dev, ib_dev->port_data[p].cache.gid); 89162306a36Sopenharmony_ci ib_dev->port_data[p].cache.gid = NULL; 89262306a36Sopenharmony_ci } 89362306a36Sopenharmony_ci} 89462306a36Sopenharmony_ci 89562306a36Sopenharmony_cistatic int _gid_table_setup_one(struct ib_device *ib_dev) 89662306a36Sopenharmony_ci{ 89762306a36Sopenharmony_ci struct ib_gid_table *table; 89862306a36Sopenharmony_ci u32 rdma_port; 89962306a36Sopenharmony_ci 90062306a36Sopenharmony_ci rdma_for_each_port (ib_dev, rdma_port) { 90162306a36Sopenharmony_ci table = alloc_gid_table( 90262306a36Sopenharmony_ci ib_dev->port_data[rdma_port].immutable.gid_tbl_len); 90362306a36Sopenharmony_ci if (!table) 90462306a36Sopenharmony_ci goto rollback_table_setup; 90562306a36Sopenharmony_ci 90662306a36Sopenharmony_ci gid_table_reserve_default(ib_dev, rdma_port, table); 90762306a36Sopenharmony_ci ib_dev->port_data[rdma_port].cache.gid = table; 90862306a36Sopenharmony_ci } 90962306a36Sopenharmony_ci return 0; 91062306a36Sopenharmony_ci 91162306a36Sopenharmony_cirollback_table_setup: 91262306a36Sopenharmony_ci gid_table_release_one(ib_dev); 91362306a36Sopenharmony_ci return -ENOMEM; 91462306a36Sopenharmony_ci} 91562306a36Sopenharmony_ci 91662306a36Sopenharmony_cistatic void gid_table_cleanup_one(struct ib_device *ib_dev) 91762306a36Sopenharmony_ci{ 91862306a36Sopenharmony_ci u32 p; 91962306a36Sopenharmony_ci 92062306a36Sopenharmony_ci rdma_for_each_port (ib_dev, p) 92162306a36Sopenharmony_ci cleanup_gid_table_port(ib_dev, p, 92262306a36Sopenharmony_ci ib_dev->port_data[p].cache.gid); 92362306a36Sopenharmony_ci} 92462306a36Sopenharmony_ci 92562306a36Sopenharmony_cistatic int gid_table_setup_one(struct ib_device *ib_dev) 92662306a36Sopenharmony_ci{ 92762306a36Sopenharmony_ci int err; 92862306a36Sopenharmony_ci 92962306a36Sopenharmony_ci err = _gid_table_setup_one(ib_dev); 93062306a36Sopenharmony_ci 93162306a36Sopenharmony_ci if (err) 93262306a36Sopenharmony_ci return err; 93362306a36Sopenharmony_ci 93462306a36Sopenharmony_ci rdma_roce_rescan_device(ib_dev); 93562306a36Sopenharmony_ci 93662306a36Sopenharmony_ci return err; 93762306a36Sopenharmony_ci} 93862306a36Sopenharmony_ci 93962306a36Sopenharmony_ci/** 94062306a36Sopenharmony_ci * rdma_query_gid - Read the GID content from the GID software cache 94162306a36Sopenharmony_ci * @device: Device to query the GID 94262306a36Sopenharmony_ci * @port_num: Port number of the device 94362306a36Sopenharmony_ci * @index: Index of the GID table entry to read 94462306a36Sopenharmony_ci * @gid: Pointer to GID where to store the entry's GID 94562306a36Sopenharmony_ci * 94662306a36Sopenharmony_ci * rdma_query_gid() only reads the GID entry content for requested device, 94762306a36Sopenharmony_ci * port and index. It reads for IB, RoCE and iWarp link layers. It doesn't 94862306a36Sopenharmony_ci * hold any reference to the GID table entry in the HCA or software cache. 94962306a36Sopenharmony_ci * 95062306a36Sopenharmony_ci * Returns 0 on success or appropriate error code. 95162306a36Sopenharmony_ci * 95262306a36Sopenharmony_ci */ 95362306a36Sopenharmony_ciint rdma_query_gid(struct ib_device *device, u32 port_num, 95462306a36Sopenharmony_ci int index, union ib_gid *gid) 95562306a36Sopenharmony_ci{ 95662306a36Sopenharmony_ci struct ib_gid_table *table; 95762306a36Sopenharmony_ci unsigned long flags; 95862306a36Sopenharmony_ci int res; 95962306a36Sopenharmony_ci 96062306a36Sopenharmony_ci if (!rdma_is_port_valid(device, port_num)) 96162306a36Sopenharmony_ci return -EINVAL; 96262306a36Sopenharmony_ci 96362306a36Sopenharmony_ci table = rdma_gid_table(device, port_num); 96462306a36Sopenharmony_ci read_lock_irqsave(&table->rwlock, flags); 96562306a36Sopenharmony_ci 96662306a36Sopenharmony_ci if (index < 0 || index >= table->sz) { 96762306a36Sopenharmony_ci res = -EINVAL; 96862306a36Sopenharmony_ci goto done; 96962306a36Sopenharmony_ci } 97062306a36Sopenharmony_ci 97162306a36Sopenharmony_ci if (!is_gid_entry_valid(table->data_vec[index])) { 97262306a36Sopenharmony_ci res = -ENOENT; 97362306a36Sopenharmony_ci goto done; 97462306a36Sopenharmony_ci } 97562306a36Sopenharmony_ci 97662306a36Sopenharmony_ci memcpy(gid, &table->data_vec[index]->attr.gid, sizeof(*gid)); 97762306a36Sopenharmony_ci res = 0; 97862306a36Sopenharmony_ci 97962306a36Sopenharmony_cidone: 98062306a36Sopenharmony_ci read_unlock_irqrestore(&table->rwlock, flags); 98162306a36Sopenharmony_ci return res; 98262306a36Sopenharmony_ci} 98362306a36Sopenharmony_ciEXPORT_SYMBOL(rdma_query_gid); 98462306a36Sopenharmony_ci 98562306a36Sopenharmony_ci/** 98662306a36Sopenharmony_ci * rdma_read_gid_hw_context - Read the HW GID context from GID attribute 98762306a36Sopenharmony_ci * @attr: Potinter to the GID attribute 98862306a36Sopenharmony_ci * 98962306a36Sopenharmony_ci * rdma_read_gid_hw_context() reads the drivers GID HW context corresponding 99062306a36Sopenharmony_ci * to the SGID attr. Callers are required to already be holding the reference 99162306a36Sopenharmony_ci * to an existing GID entry. 99262306a36Sopenharmony_ci * 99362306a36Sopenharmony_ci * Returns the HW GID context 99462306a36Sopenharmony_ci * 99562306a36Sopenharmony_ci */ 99662306a36Sopenharmony_civoid *rdma_read_gid_hw_context(const struct ib_gid_attr *attr) 99762306a36Sopenharmony_ci{ 99862306a36Sopenharmony_ci return container_of(attr, struct ib_gid_table_entry, attr)->context; 99962306a36Sopenharmony_ci} 100062306a36Sopenharmony_ciEXPORT_SYMBOL(rdma_read_gid_hw_context); 100162306a36Sopenharmony_ci 100262306a36Sopenharmony_ci/** 100362306a36Sopenharmony_ci * rdma_find_gid - Returns SGID attributes if the matching GID is found. 100462306a36Sopenharmony_ci * @device: The device to query. 100562306a36Sopenharmony_ci * @gid: The GID value to search for. 100662306a36Sopenharmony_ci * @gid_type: The GID type to search for. 100762306a36Sopenharmony_ci * @ndev: In RoCE, the net device of the device. NULL means ignore. 100862306a36Sopenharmony_ci * 100962306a36Sopenharmony_ci * rdma_find_gid() searches for the specified GID value in the software cache. 101062306a36Sopenharmony_ci * 101162306a36Sopenharmony_ci * Returns GID attributes if a valid GID is found or returns ERR_PTR for the 101262306a36Sopenharmony_ci * error. The caller must invoke rdma_put_gid_attr() to release the reference. 101362306a36Sopenharmony_ci * 101462306a36Sopenharmony_ci */ 101562306a36Sopenharmony_ciconst struct ib_gid_attr *rdma_find_gid(struct ib_device *device, 101662306a36Sopenharmony_ci const union ib_gid *gid, 101762306a36Sopenharmony_ci enum ib_gid_type gid_type, 101862306a36Sopenharmony_ci struct net_device *ndev) 101962306a36Sopenharmony_ci{ 102062306a36Sopenharmony_ci unsigned long mask = GID_ATTR_FIND_MASK_GID | 102162306a36Sopenharmony_ci GID_ATTR_FIND_MASK_GID_TYPE; 102262306a36Sopenharmony_ci struct ib_gid_attr gid_attr_val = {.ndev = ndev, .gid_type = gid_type}; 102362306a36Sopenharmony_ci u32 p; 102462306a36Sopenharmony_ci 102562306a36Sopenharmony_ci if (ndev) 102662306a36Sopenharmony_ci mask |= GID_ATTR_FIND_MASK_NETDEV; 102762306a36Sopenharmony_ci 102862306a36Sopenharmony_ci rdma_for_each_port(device, p) { 102962306a36Sopenharmony_ci struct ib_gid_table *table; 103062306a36Sopenharmony_ci unsigned long flags; 103162306a36Sopenharmony_ci int index; 103262306a36Sopenharmony_ci 103362306a36Sopenharmony_ci table = device->port_data[p].cache.gid; 103462306a36Sopenharmony_ci read_lock_irqsave(&table->rwlock, flags); 103562306a36Sopenharmony_ci index = find_gid(table, gid, &gid_attr_val, false, mask, NULL); 103662306a36Sopenharmony_ci if (index >= 0) { 103762306a36Sopenharmony_ci const struct ib_gid_attr *attr; 103862306a36Sopenharmony_ci 103962306a36Sopenharmony_ci get_gid_entry(table->data_vec[index]); 104062306a36Sopenharmony_ci attr = &table->data_vec[index]->attr; 104162306a36Sopenharmony_ci read_unlock_irqrestore(&table->rwlock, flags); 104262306a36Sopenharmony_ci return attr; 104362306a36Sopenharmony_ci } 104462306a36Sopenharmony_ci read_unlock_irqrestore(&table->rwlock, flags); 104562306a36Sopenharmony_ci } 104662306a36Sopenharmony_ci 104762306a36Sopenharmony_ci return ERR_PTR(-ENOENT); 104862306a36Sopenharmony_ci} 104962306a36Sopenharmony_ciEXPORT_SYMBOL(rdma_find_gid); 105062306a36Sopenharmony_ci 105162306a36Sopenharmony_ciint ib_get_cached_pkey(struct ib_device *device, 105262306a36Sopenharmony_ci u32 port_num, 105362306a36Sopenharmony_ci int index, 105462306a36Sopenharmony_ci u16 *pkey) 105562306a36Sopenharmony_ci{ 105662306a36Sopenharmony_ci struct ib_pkey_cache *cache; 105762306a36Sopenharmony_ci unsigned long flags; 105862306a36Sopenharmony_ci int ret = 0; 105962306a36Sopenharmony_ci 106062306a36Sopenharmony_ci if (!rdma_is_port_valid(device, port_num)) 106162306a36Sopenharmony_ci return -EINVAL; 106262306a36Sopenharmony_ci 106362306a36Sopenharmony_ci read_lock_irqsave(&device->cache_lock, flags); 106462306a36Sopenharmony_ci 106562306a36Sopenharmony_ci cache = device->port_data[port_num].cache.pkey; 106662306a36Sopenharmony_ci 106762306a36Sopenharmony_ci if (!cache || index < 0 || index >= cache->table_len) 106862306a36Sopenharmony_ci ret = -EINVAL; 106962306a36Sopenharmony_ci else 107062306a36Sopenharmony_ci *pkey = cache->table[index]; 107162306a36Sopenharmony_ci 107262306a36Sopenharmony_ci read_unlock_irqrestore(&device->cache_lock, flags); 107362306a36Sopenharmony_ci 107462306a36Sopenharmony_ci return ret; 107562306a36Sopenharmony_ci} 107662306a36Sopenharmony_ciEXPORT_SYMBOL(ib_get_cached_pkey); 107762306a36Sopenharmony_ci 107862306a36Sopenharmony_civoid ib_get_cached_subnet_prefix(struct ib_device *device, u32 port_num, 107962306a36Sopenharmony_ci u64 *sn_pfx) 108062306a36Sopenharmony_ci{ 108162306a36Sopenharmony_ci unsigned long flags; 108262306a36Sopenharmony_ci 108362306a36Sopenharmony_ci read_lock_irqsave(&device->cache_lock, flags); 108462306a36Sopenharmony_ci *sn_pfx = device->port_data[port_num].cache.subnet_prefix; 108562306a36Sopenharmony_ci read_unlock_irqrestore(&device->cache_lock, flags); 108662306a36Sopenharmony_ci} 108762306a36Sopenharmony_ciEXPORT_SYMBOL(ib_get_cached_subnet_prefix); 108862306a36Sopenharmony_ci 108962306a36Sopenharmony_ciint ib_find_cached_pkey(struct ib_device *device, u32 port_num, 109062306a36Sopenharmony_ci u16 pkey, u16 *index) 109162306a36Sopenharmony_ci{ 109262306a36Sopenharmony_ci struct ib_pkey_cache *cache; 109362306a36Sopenharmony_ci unsigned long flags; 109462306a36Sopenharmony_ci int i; 109562306a36Sopenharmony_ci int ret = -ENOENT; 109662306a36Sopenharmony_ci int partial_ix = -1; 109762306a36Sopenharmony_ci 109862306a36Sopenharmony_ci if (!rdma_is_port_valid(device, port_num)) 109962306a36Sopenharmony_ci return -EINVAL; 110062306a36Sopenharmony_ci 110162306a36Sopenharmony_ci read_lock_irqsave(&device->cache_lock, flags); 110262306a36Sopenharmony_ci 110362306a36Sopenharmony_ci cache = device->port_data[port_num].cache.pkey; 110462306a36Sopenharmony_ci if (!cache) { 110562306a36Sopenharmony_ci ret = -EINVAL; 110662306a36Sopenharmony_ci goto err; 110762306a36Sopenharmony_ci } 110862306a36Sopenharmony_ci 110962306a36Sopenharmony_ci *index = -1; 111062306a36Sopenharmony_ci 111162306a36Sopenharmony_ci for (i = 0; i < cache->table_len; ++i) 111262306a36Sopenharmony_ci if ((cache->table[i] & 0x7fff) == (pkey & 0x7fff)) { 111362306a36Sopenharmony_ci if (cache->table[i] & 0x8000) { 111462306a36Sopenharmony_ci *index = i; 111562306a36Sopenharmony_ci ret = 0; 111662306a36Sopenharmony_ci break; 111762306a36Sopenharmony_ci } else { 111862306a36Sopenharmony_ci partial_ix = i; 111962306a36Sopenharmony_ci } 112062306a36Sopenharmony_ci } 112162306a36Sopenharmony_ci 112262306a36Sopenharmony_ci if (ret && partial_ix >= 0) { 112362306a36Sopenharmony_ci *index = partial_ix; 112462306a36Sopenharmony_ci ret = 0; 112562306a36Sopenharmony_ci } 112662306a36Sopenharmony_ci 112762306a36Sopenharmony_cierr: 112862306a36Sopenharmony_ci read_unlock_irqrestore(&device->cache_lock, flags); 112962306a36Sopenharmony_ci 113062306a36Sopenharmony_ci return ret; 113162306a36Sopenharmony_ci} 113262306a36Sopenharmony_ciEXPORT_SYMBOL(ib_find_cached_pkey); 113362306a36Sopenharmony_ci 113462306a36Sopenharmony_ciint ib_find_exact_cached_pkey(struct ib_device *device, u32 port_num, 113562306a36Sopenharmony_ci u16 pkey, u16 *index) 113662306a36Sopenharmony_ci{ 113762306a36Sopenharmony_ci struct ib_pkey_cache *cache; 113862306a36Sopenharmony_ci unsigned long flags; 113962306a36Sopenharmony_ci int i; 114062306a36Sopenharmony_ci int ret = -ENOENT; 114162306a36Sopenharmony_ci 114262306a36Sopenharmony_ci if (!rdma_is_port_valid(device, port_num)) 114362306a36Sopenharmony_ci return -EINVAL; 114462306a36Sopenharmony_ci 114562306a36Sopenharmony_ci read_lock_irqsave(&device->cache_lock, flags); 114662306a36Sopenharmony_ci 114762306a36Sopenharmony_ci cache = device->port_data[port_num].cache.pkey; 114862306a36Sopenharmony_ci if (!cache) { 114962306a36Sopenharmony_ci ret = -EINVAL; 115062306a36Sopenharmony_ci goto err; 115162306a36Sopenharmony_ci } 115262306a36Sopenharmony_ci 115362306a36Sopenharmony_ci *index = -1; 115462306a36Sopenharmony_ci 115562306a36Sopenharmony_ci for (i = 0; i < cache->table_len; ++i) 115662306a36Sopenharmony_ci if (cache->table[i] == pkey) { 115762306a36Sopenharmony_ci *index = i; 115862306a36Sopenharmony_ci ret = 0; 115962306a36Sopenharmony_ci break; 116062306a36Sopenharmony_ci } 116162306a36Sopenharmony_ci 116262306a36Sopenharmony_cierr: 116362306a36Sopenharmony_ci read_unlock_irqrestore(&device->cache_lock, flags); 116462306a36Sopenharmony_ci 116562306a36Sopenharmony_ci return ret; 116662306a36Sopenharmony_ci} 116762306a36Sopenharmony_ciEXPORT_SYMBOL(ib_find_exact_cached_pkey); 116862306a36Sopenharmony_ci 116962306a36Sopenharmony_ciint ib_get_cached_lmc(struct ib_device *device, u32 port_num, u8 *lmc) 117062306a36Sopenharmony_ci{ 117162306a36Sopenharmony_ci unsigned long flags; 117262306a36Sopenharmony_ci int ret = 0; 117362306a36Sopenharmony_ci 117462306a36Sopenharmony_ci if (!rdma_is_port_valid(device, port_num)) 117562306a36Sopenharmony_ci return -EINVAL; 117662306a36Sopenharmony_ci 117762306a36Sopenharmony_ci read_lock_irqsave(&device->cache_lock, flags); 117862306a36Sopenharmony_ci *lmc = device->port_data[port_num].cache.lmc; 117962306a36Sopenharmony_ci read_unlock_irqrestore(&device->cache_lock, flags); 118062306a36Sopenharmony_ci 118162306a36Sopenharmony_ci return ret; 118262306a36Sopenharmony_ci} 118362306a36Sopenharmony_ciEXPORT_SYMBOL(ib_get_cached_lmc); 118462306a36Sopenharmony_ci 118562306a36Sopenharmony_ciint ib_get_cached_port_state(struct ib_device *device, u32 port_num, 118662306a36Sopenharmony_ci enum ib_port_state *port_state) 118762306a36Sopenharmony_ci{ 118862306a36Sopenharmony_ci unsigned long flags; 118962306a36Sopenharmony_ci int ret = 0; 119062306a36Sopenharmony_ci 119162306a36Sopenharmony_ci if (!rdma_is_port_valid(device, port_num)) 119262306a36Sopenharmony_ci return -EINVAL; 119362306a36Sopenharmony_ci 119462306a36Sopenharmony_ci read_lock_irqsave(&device->cache_lock, flags); 119562306a36Sopenharmony_ci *port_state = device->port_data[port_num].cache.port_state; 119662306a36Sopenharmony_ci read_unlock_irqrestore(&device->cache_lock, flags); 119762306a36Sopenharmony_ci 119862306a36Sopenharmony_ci return ret; 119962306a36Sopenharmony_ci} 120062306a36Sopenharmony_ciEXPORT_SYMBOL(ib_get_cached_port_state); 120162306a36Sopenharmony_ci 120262306a36Sopenharmony_ci/** 120362306a36Sopenharmony_ci * rdma_get_gid_attr - Returns GID attributes for a port of a device 120462306a36Sopenharmony_ci * at a requested gid_index, if a valid GID entry exists. 120562306a36Sopenharmony_ci * @device: The device to query. 120662306a36Sopenharmony_ci * @port_num: The port number on the device where the GID value 120762306a36Sopenharmony_ci * is to be queried. 120862306a36Sopenharmony_ci * @index: Index of the GID table entry whose attributes are to 120962306a36Sopenharmony_ci * be queried. 121062306a36Sopenharmony_ci * 121162306a36Sopenharmony_ci * rdma_get_gid_attr() acquires reference count of gid attributes from the 121262306a36Sopenharmony_ci * cached GID table. Caller must invoke rdma_put_gid_attr() to release 121362306a36Sopenharmony_ci * reference to gid attribute regardless of link layer. 121462306a36Sopenharmony_ci * 121562306a36Sopenharmony_ci * Returns pointer to valid gid attribute or ERR_PTR for the appropriate error 121662306a36Sopenharmony_ci * code. 121762306a36Sopenharmony_ci */ 121862306a36Sopenharmony_ciconst struct ib_gid_attr * 121962306a36Sopenharmony_cirdma_get_gid_attr(struct ib_device *device, u32 port_num, int index) 122062306a36Sopenharmony_ci{ 122162306a36Sopenharmony_ci const struct ib_gid_attr *attr = ERR_PTR(-ENODATA); 122262306a36Sopenharmony_ci struct ib_gid_table *table; 122362306a36Sopenharmony_ci unsigned long flags; 122462306a36Sopenharmony_ci 122562306a36Sopenharmony_ci if (!rdma_is_port_valid(device, port_num)) 122662306a36Sopenharmony_ci return ERR_PTR(-EINVAL); 122762306a36Sopenharmony_ci 122862306a36Sopenharmony_ci table = rdma_gid_table(device, port_num); 122962306a36Sopenharmony_ci if (index < 0 || index >= table->sz) 123062306a36Sopenharmony_ci return ERR_PTR(-EINVAL); 123162306a36Sopenharmony_ci 123262306a36Sopenharmony_ci read_lock_irqsave(&table->rwlock, flags); 123362306a36Sopenharmony_ci if (!is_gid_entry_valid(table->data_vec[index])) 123462306a36Sopenharmony_ci goto done; 123562306a36Sopenharmony_ci 123662306a36Sopenharmony_ci get_gid_entry(table->data_vec[index]); 123762306a36Sopenharmony_ci attr = &table->data_vec[index]->attr; 123862306a36Sopenharmony_cidone: 123962306a36Sopenharmony_ci read_unlock_irqrestore(&table->rwlock, flags); 124062306a36Sopenharmony_ci return attr; 124162306a36Sopenharmony_ci} 124262306a36Sopenharmony_ciEXPORT_SYMBOL(rdma_get_gid_attr); 124362306a36Sopenharmony_ci 124462306a36Sopenharmony_ci/** 124562306a36Sopenharmony_ci * rdma_query_gid_table - Reads GID table entries of all the ports of a device up to max_entries. 124662306a36Sopenharmony_ci * @device: The device to query. 124762306a36Sopenharmony_ci * @entries: Entries where GID entries are returned. 124862306a36Sopenharmony_ci * @max_entries: Maximum number of entries that can be returned. 124962306a36Sopenharmony_ci * Entries array must be allocated to hold max_entries number of entries. 125062306a36Sopenharmony_ci * 125162306a36Sopenharmony_ci * Returns number of entries on success or appropriate error code. 125262306a36Sopenharmony_ci */ 125362306a36Sopenharmony_cissize_t rdma_query_gid_table(struct ib_device *device, 125462306a36Sopenharmony_ci struct ib_uverbs_gid_entry *entries, 125562306a36Sopenharmony_ci size_t max_entries) 125662306a36Sopenharmony_ci{ 125762306a36Sopenharmony_ci const struct ib_gid_attr *gid_attr; 125862306a36Sopenharmony_ci ssize_t num_entries = 0, ret; 125962306a36Sopenharmony_ci struct ib_gid_table *table; 126062306a36Sopenharmony_ci u32 port_num, i; 126162306a36Sopenharmony_ci struct net_device *ndev; 126262306a36Sopenharmony_ci unsigned long flags; 126362306a36Sopenharmony_ci 126462306a36Sopenharmony_ci rdma_for_each_port(device, port_num) { 126562306a36Sopenharmony_ci table = rdma_gid_table(device, port_num); 126662306a36Sopenharmony_ci read_lock_irqsave(&table->rwlock, flags); 126762306a36Sopenharmony_ci for (i = 0; i < table->sz; i++) { 126862306a36Sopenharmony_ci if (!is_gid_entry_valid(table->data_vec[i])) 126962306a36Sopenharmony_ci continue; 127062306a36Sopenharmony_ci if (num_entries >= max_entries) { 127162306a36Sopenharmony_ci ret = -EINVAL; 127262306a36Sopenharmony_ci goto err; 127362306a36Sopenharmony_ci } 127462306a36Sopenharmony_ci 127562306a36Sopenharmony_ci gid_attr = &table->data_vec[i]->attr; 127662306a36Sopenharmony_ci 127762306a36Sopenharmony_ci memcpy(&entries->gid, &gid_attr->gid, 127862306a36Sopenharmony_ci sizeof(gid_attr->gid)); 127962306a36Sopenharmony_ci entries->gid_index = gid_attr->index; 128062306a36Sopenharmony_ci entries->port_num = gid_attr->port_num; 128162306a36Sopenharmony_ci entries->gid_type = gid_attr->gid_type; 128262306a36Sopenharmony_ci ndev = rcu_dereference_protected( 128362306a36Sopenharmony_ci gid_attr->ndev, 128462306a36Sopenharmony_ci lockdep_is_held(&table->rwlock)); 128562306a36Sopenharmony_ci if (ndev) 128662306a36Sopenharmony_ci entries->netdev_ifindex = ndev->ifindex; 128762306a36Sopenharmony_ci 128862306a36Sopenharmony_ci num_entries++; 128962306a36Sopenharmony_ci entries++; 129062306a36Sopenharmony_ci } 129162306a36Sopenharmony_ci read_unlock_irqrestore(&table->rwlock, flags); 129262306a36Sopenharmony_ci } 129362306a36Sopenharmony_ci 129462306a36Sopenharmony_ci return num_entries; 129562306a36Sopenharmony_cierr: 129662306a36Sopenharmony_ci read_unlock_irqrestore(&table->rwlock, flags); 129762306a36Sopenharmony_ci return ret; 129862306a36Sopenharmony_ci} 129962306a36Sopenharmony_ciEXPORT_SYMBOL(rdma_query_gid_table); 130062306a36Sopenharmony_ci 130162306a36Sopenharmony_ci/** 130262306a36Sopenharmony_ci * rdma_put_gid_attr - Release reference to the GID attribute 130362306a36Sopenharmony_ci * @attr: Pointer to the GID attribute whose reference 130462306a36Sopenharmony_ci * needs to be released. 130562306a36Sopenharmony_ci * 130662306a36Sopenharmony_ci * rdma_put_gid_attr() must be used to release reference whose 130762306a36Sopenharmony_ci * reference is acquired using rdma_get_gid_attr() or any APIs 130862306a36Sopenharmony_ci * which returns a pointer to the ib_gid_attr regardless of link layer 130962306a36Sopenharmony_ci * of IB or RoCE. 131062306a36Sopenharmony_ci * 131162306a36Sopenharmony_ci */ 131262306a36Sopenharmony_civoid rdma_put_gid_attr(const struct ib_gid_attr *attr) 131362306a36Sopenharmony_ci{ 131462306a36Sopenharmony_ci struct ib_gid_table_entry *entry = 131562306a36Sopenharmony_ci container_of(attr, struct ib_gid_table_entry, attr); 131662306a36Sopenharmony_ci 131762306a36Sopenharmony_ci put_gid_entry(entry); 131862306a36Sopenharmony_ci} 131962306a36Sopenharmony_ciEXPORT_SYMBOL(rdma_put_gid_attr); 132062306a36Sopenharmony_ci 132162306a36Sopenharmony_ci/** 132262306a36Sopenharmony_ci * rdma_hold_gid_attr - Get reference to existing GID attribute 132362306a36Sopenharmony_ci * 132462306a36Sopenharmony_ci * @attr: Pointer to the GID attribute whose reference 132562306a36Sopenharmony_ci * needs to be taken. 132662306a36Sopenharmony_ci * 132762306a36Sopenharmony_ci * Increase the reference count to a GID attribute to keep it from being 132862306a36Sopenharmony_ci * freed. Callers are required to already be holding a reference to attribute. 132962306a36Sopenharmony_ci * 133062306a36Sopenharmony_ci */ 133162306a36Sopenharmony_civoid rdma_hold_gid_attr(const struct ib_gid_attr *attr) 133262306a36Sopenharmony_ci{ 133362306a36Sopenharmony_ci struct ib_gid_table_entry *entry = 133462306a36Sopenharmony_ci container_of(attr, struct ib_gid_table_entry, attr); 133562306a36Sopenharmony_ci 133662306a36Sopenharmony_ci get_gid_entry(entry); 133762306a36Sopenharmony_ci} 133862306a36Sopenharmony_ciEXPORT_SYMBOL(rdma_hold_gid_attr); 133962306a36Sopenharmony_ci 134062306a36Sopenharmony_ci/** 134162306a36Sopenharmony_ci * rdma_read_gid_attr_ndev_rcu - Read GID attribute netdevice 134262306a36Sopenharmony_ci * which must be in UP state. 134362306a36Sopenharmony_ci * 134462306a36Sopenharmony_ci * @attr:Pointer to the GID attribute 134562306a36Sopenharmony_ci * 134662306a36Sopenharmony_ci * Returns pointer to netdevice if the netdevice was attached to GID and 134762306a36Sopenharmony_ci * netdevice is in UP state. Caller must hold RCU lock as this API 134862306a36Sopenharmony_ci * reads the netdev flags which can change while netdevice migrates to 134962306a36Sopenharmony_ci * different net namespace. Returns ERR_PTR with error code otherwise. 135062306a36Sopenharmony_ci * 135162306a36Sopenharmony_ci */ 135262306a36Sopenharmony_cistruct net_device *rdma_read_gid_attr_ndev_rcu(const struct ib_gid_attr *attr) 135362306a36Sopenharmony_ci{ 135462306a36Sopenharmony_ci struct ib_gid_table_entry *entry = 135562306a36Sopenharmony_ci container_of(attr, struct ib_gid_table_entry, attr); 135662306a36Sopenharmony_ci struct ib_device *device = entry->attr.device; 135762306a36Sopenharmony_ci struct net_device *ndev = ERR_PTR(-EINVAL); 135862306a36Sopenharmony_ci u32 port_num = entry->attr.port_num; 135962306a36Sopenharmony_ci struct ib_gid_table *table; 136062306a36Sopenharmony_ci unsigned long flags; 136162306a36Sopenharmony_ci bool valid; 136262306a36Sopenharmony_ci 136362306a36Sopenharmony_ci table = rdma_gid_table(device, port_num); 136462306a36Sopenharmony_ci 136562306a36Sopenharmony_ci read_lock_irqsave(&table->rwlock, flags); 136662306a36Sopenharmony_ci valid = is_gid_entry_valid(table->data_vec[attr->index]); 136762306a36Sopenharmony_ci if (valid) { 136862306a36Sopenharmony_ci ndev = rcu_dereference(attr->ndev); 136962306a36Sopenharmony_ci if (!ndev) 137062306a36Sopenharmony_ci ndev = ERR_PTR(-ENODEV); 137162306a36Sopenharmony_ci } 137262306a36Sopenharmony_ci read_unlock_irqrestore(&table->rwlock, flags); 137362306a36Sopenharmony_ci return ndev; 137462306a36Sopenharmony_ci} 137562306a36Sopenharmony_ciEXPORT_SYMBOL(rdma_read_gid_attr_ndev_rcu); 137662306a36Sopenharmony_ci 137762306a36Sopenharmony_cistatic int get_lower_dev_vlan(struct net_device *lower_dev, 137862306a36Sopenharmony_ci struct netdev_nested_priv *priv) 137962306a36Sopenharmony_ci{ 138062306a36Sopenharmony_ci u16 *vlan_id = (u16 *)priv->data; 138162306a36Sopenharmony_ci 138262306a36Sopenharmony_ci if (is_vlan_dev(lower_dev)) 138362306a36Sopenharmony_ci *vlan_id = vlan_dev_vlan_id(lower_dev); 138462306a36Sopenharmony_ci 138562306a36Sopenharmony_ci /* We are interested only in first level vlan device, so 138662306a36Sopenharmony_ci * always return 1 to stop iterating over next level devices. 138762306a36Sopenharmony_ci */ 138862306a36Sopenharmony_ci return 1; 138962306a36Sopenharmony_ci} 139062306a36Sopenharmony_ci 139162306a36Sopenharmony_ci/** 139262306a36Sopenharmony_ci * rdma_read_gid_l2_fields - Read the vlan ID and source MAC address 139362306a36Sopenharmony_ci * of a GID entry. 139462306a36Sopenharmony_ci * 139562306a36Sopenharmony_ci * @attr: GID attribute pointer whose L2 fields to be read 139662306a36Sopenharmony_ci * @vlan_id: Pointer to vlan id to fill up if the GID entry has 139762306a36Sopenharmony_ci * vlan id. It is optional. 139862306a36Sopenharmony_ci * @smac: Pointer to smac to fill up for a GID entry. It is optional. 139962306a36Sopenharmony_ci * 140062306a36Sopenharmony_ci * rdma_read_gid_l2_fields() returns 0 on success and returns vlan id 140162306a36Sopenharmony_ci * (if gid entry has vlan) and source MAC, or returns error. 140262306a36Sopenharmony_ci */ 140362306a36Sopenharmony_ciint rdma_read_gid_l2_fields(const struct ib_gid_attr *attr, 140462306a36Sopenharmony_ci u16 *vlan_id, u8 *smac) 140562306a36Sopenharmony_ci{ 140662306a36Sopenharmony_ci struct netdev_nested_priv priv = { 140762306a36Sopenharmony_ci .data = (void *)vlan_id, 140862306a36Sopenharmony_ci }; 140962306a36Sopenharmony_ci struct net_device *ndev; 141062306a36Sopenharmony_ci 141162306a36Sopenharmony_ci rcu_read_lock(); 141262306a36Sopenharmony_ci ndev = rcu_dereference(attr->ndev); 141362306a36Sopenharmony_ci if (!ndev) { 141462306a36Sopenharmony_ci rcu_read_unlock(); 141562306a36Sopenharmony_ci return -ENODEV; 141662306a36Sopenharmony_ci } 141762306a36Sopenharmony_ci if (smac) 141862306a36Sopenharmony_ci ether_addr_copy(smac, ndev->dev_addr); 141962306a36Sopenharmony_ci if (vlan_id) { 142062306a36Sopenharmony_ci *vlan_id = 0xffff; 142162306a36Sopenharmony_ci if (is_vlan_dev(ndev)) { 142262306a36Sopenharmony_ci *vlan_id = vlan_dev_vlan_id(ndev); 142362306a36Sopenharmony_ci } else { 142462306a36Sopenharmony_ci /* If the netdev is upper device and if it's lower 142562306a36Sopenharmony_ci * device is vlan device, consider vlan id of 142662306a36Sopenharmony_ci * the lower vlan device for this gid entry. 142762306a36Sopenharmony_ci */ 142862306a36Sopenharmony_ci netdev_walk_all_lower_dev_rcu(attr->ndev, 142962306a36Sopenharmony_ci get_lower_dev_vlan, &priv); 143062306a36Sopenharmony_ci } 143162306a36Sopenharmony_ci } 143262306a36Sopenharmony_ci rcu_read_unlock(); 143362306a36Sopenharmony_ci return 0; 143462306a36Sopenharmony_ci} 143562306a36Sopenharmony_ciEXPORT_SYMBOL(rdma_read_gid_l2_fields); 143662306a36Sopenharmony_ci 143762306a36Sopenharmony_cistatic int config_non_roce_gid_cache(struct ib_device *device, 143862306a36Sopenharmony_ci u32 port, struct ib_port_attr *tprops) 143962306a36Sopenharmony_ci{ 144062306a36Sopenharmony_ci struct ib_gid_attr gid_attr = {}; 144162306a36Sopenharmony_ci struct ib_gid_table *table; 144262306a36Sopenharmony_ci int ret = 0; 144362306a36Sopenharmony_ci int i; 144462306a36Sopenharmony_ci 144562306a36Sopenharmony_ci gid_attr.device = device; 144662306a36Sopenharmony_ci gid_attr.port_num = port; 144762306a36Sopenharmony_ci table = rdma_gid_table(device, port); 144862306a36Sopenharmony_ci 144962306a36Sopenharmony_ci mutex_lock(&table->lock); 145062306a36Sopenharmony_ci for (i = 0; i < tprops->gid_tbl_len; ++i) { 145162306a36Sopenharmony_ci if (!device->ops.query_gid) 145262306a36Sopenharmony_ci continue; 145362306a36Sopenharmony_ci ret = device->ops.query_gid(device, port, i, &gid_attr.gid); 145462306a36Sopenharmony_ci if (ret) { 145562306a36Sopenharmony_ci dev_warn(&device->dev, 145662306a36Sopenharmony_ci "query_gid failed (%d) for index %d\n", ret, 145762306a36Sopenharmony_ci i); 145862306a36Sopenharmony_ci goto err; 145962306a36Sopenharmony_ci } 146062306a36Sopenharmony_ci 146162306a36Sopenharmony_ci if (rdma_protocol_iwarp(device, port)) { 146262306a36Sopenharmony_ci struct net_device *ndev; 146362306a36Sopenharmony_ci 146462306a36Sopenharmony_ci ndev = ib_device_get_netdev(device, port); 146562306a36Sopenharmony_ci if (!ndev) 146662306a36Sopenharmony_ci continue; 146762306a36Sopenharmony_ci RCU_INIT_POINTER(gid_attr.ndev, ndev); 146862306a36Sopenharmony_ci dev_put(ndev); 146962306a36Sopenharmony_ci } 147062306a36Sopenharmony_ci 147162306a36Sopenharmony_ci gid_attr.index = i; 147262306a36Sopenharmony_ci tprops->subnet_prefix = 147362306a36Sopenharmony_ci be64_to_cpu(gid_attr.gid.global.subnet_prefix); 147462306a36Sopenharmony_ci add_modify_gid(table, &gid_attr); 147562306a36Sopenharmony_ci } 147662306a36Sopenharmony_cierr: 147762306a36Sopenharmony_ci mutex_unlock(&table->lock); 147862306a36Sopenharmony_ci return ret; 147962306a36Sopenharmony_ci} 148062306a36Sopenharmony_ci 148162306a36Sopenharmony_cistatic int 148262306a36Sopenharmony_ciib_cache_update(struct ib_device *device, u32 port, bool update_gids, 148362306a36Sopenharmony_ci bool update_pkeys, bool enforce_security) 148462306a36Sopenharmony_ci{ 148562306a36Sopenharmony_ci struct ib_port_attr *tprops = NULL; 148662306a36Sopenharmony_ci struct ib_pkey_cache *pkey_cache = NULL; 148762306a36Sopenharmony_ci struct ib_pkey_cache *old_pkey_cache = NULL; 148862306a36Sopenharmony_ci int i; 148962306a36Sopenharmony_ci int ret; 149062306a36Sopenharmony_ci 149162306a36Sopenharmony_ci if (!rdma_is_port_valid(device, port)) 149262306a36Sopenharmony_ci return -EINVAL; 149362306a36Sopenharmony_ci 149462306a36Sopenharmony_ci tprops = kmalloc(sizeof *tprops, GFP_KERNEL); 149562306a36Sopenharmony_ci if (!tprops) 149662306a36Sopenharmony_ci return -ENOMEM; 149762306a36Sopenharmony_ci 149862306a36Sopenharmony_ci ret = ib_query_port(device, port, tprops); 149962306a36Sopenharmony_ci if (ret) { 150062306a36Sopenharmony_ci dev_warn(&device->dev, "ib_query_port failed (%d)\n", ret); 150162306a36Sopenharmony_ci goto err; 150262306a36Sopenharmony_ci } 150362306a36Sopenharmony_ci 150462306a36Sopenharmony_ci if (!rdma_protocol_roce(device, port) && update_gids) { 150562306a36Sopenharmony_ci ret = config_non_roce_gid_cache(device, port, 150662306a36Sopenharmony_ci tprops); 150762306a36Sopenharmony_ci if (ret) 150862306a36Sopenharmony_ci goto err; 150962306a36Sopenharmony_ci } 151062306a36Sopenharmony_ci 151162306a36Sopenharmony_ci update_pkeys &= !!tprops->pkey_tbl_len; 151262306a36Sopenharmony_ci 151362306a36Sopenharmony_ci if (update_pkeys) { 151462306a36Sopenharmony_ci pkey_cache = kmalloc(struct_size(pkey_cache, table, 151562306a36Sopenharmony_ci tprops->pkey_tbl_len), 151662306a36Sopenharmony_ci GFP_KERNEL); 151762306a36Sopenharmony_ci if (!pkey_cache) { 151862306a36Sopenharmony_ci ret = -ENOMEM; 151962306a36Sopenharmony_ci goto err; 152062306a36Sopenharmony_ci } 152162306a36Sopenharmony_ci 152262306a36Sopenharmony_ci pkey_cache->table_len = tprops->pkey_tbl_len; 152362306a36Sopenharmony_ci 152462306a36Sopenharmony_ci for (i = 0; i < pkey_cache->table_len; ++i) { 152562306a36Sopenharmony_ci ret = ib_query_pkey(device, port, i, 152662306a36Sopenharmony_ci pkey_cache->table + i); 152762306a36Sopenharmony_ci if (ret) { 152862306a36Sopenharmony_ci dev_warn(&device->dev, 152962306a36Sopenharmony_ci "ib_query_pkey failed (%d) for index %d\n", 153062306a36Sopenharmony_ci ret, i); 153162306a36Sopenharmony_ci goto err; 153262306a36Sopenharmony_ci } 153362306a36Sopenharmony_ci } 153462306a36Sopenharmony_ci } 153562306a36Sopenharmony_ci 153662306a36Sopenharmony_ci write_lock_irq(&device->cache_lock); 153762306a36Sopenharmony_ci 153862306a36Sopenharmony_ci if (update_pkeys) { 153962306a36Sopenharmony_ci old_pkey_cache = device->port_data[port].cache.pkey; 154062306a36Sopenharmony_ci device->port_data[port].cache.pkey = pkey_cache; 154162306a36Sopenharmony_ci } 154262306a36Sopenharmony_ci device->port_data[port].cache.lmc = tprops->lmc; 154362306a36Sopenharmony_ci device->port_data[port].cache.port_state = tprops->state; 154462306a36Sopenharmony_ci 154562306a36Sopenharmony_ci device->port_data[port].cache.subnet_prefix = tprops->subnet_prefix; 154662306a36Sopenharmony_ci write_unlock_irq(&device->cache_lock); 154762306a36Sopenharmony_ci 154862306a36Sopenharmony_ci if (enforce_security) 154962306a36Sopenharmony_ci ib_security_cache_change(device, 155062306a36Sopenharmony_ci port, 155162306a36Sopenharmony_ci tprops->subnet_prefix); 155262306a36Sopenharmony_ci 155362306a36Sopenharmony_ci kfree(old_pkey_cache); 155462306a36Sopenharmony_ci kfree(tprops); 155562306a36Sopenharmony_ci return 0; 155662306a36Sopenharmony_ci 155762306a36Sopenharmony_cierr: 155862306a36Sopenharmony_ci kfree(pkey_cache); 155962306a36Sopenharmony_ci kfree(tprops); 156062306a36Sopenharmony_ci return ret; 156162306a36Sopenharmony_ci} 156262306a36Sopenharmony_ci 156362306a36Sopenharmony_cistatic void ib_cache_event_task(struct work_struct *_work) 156462306a36Sopenharmony_ci{ 156562306a36Sopenharmony_ci struct ib_update_work *work = 156662306a36Sopenharmony_ci container_of(_work, struct ib_update_work, work); 156762306a36Sopenharmony_ci int ret; 156862306a36Sopenharmony_ci 156962306a36Sopenharmony_ci /* Before distributing the cache update event, first sync 157062306a36Sopenharmony_ci * the cache. 157162306a36Sopenharmony_ci */ 157262306a36Sopenharmony_ci ret = ib_cache_update(work->event.device, work->event.element.port_num, 157362306a36Sopenharmony_ci work->event.event == IB_EVENT_GID_CHANGE, 157462306a36Sopenharmony_ci work->event.event == IB_EVENT_PKEY_CHANGE, 157562306a36Sopenharmony_ci work->enforce_security); 157662306a36Sopenharmony_ci 157762306a36Sopenharmony_ci /* GID event is notified already for individual GID entries by 157862306a36Sopenharmony_ci * dispatch_gid_change_event(). Hence, notifiy for rest of the 157962306a36Sopenharmony_ci * events. 158062306a36Sopenharmony_ci */ 158162306a36Sopenharmony_ci if (!ret && work->event.event != IB_EVENT_GID_CHANGE) 158262306a36Sopenharmony_ci ib_dispatch_event_clients(&work->event); 158362306a36Sopenharmony_ci 158462306a36Sopenharmony_ci kfree(work); 158562306a36Sopenharmony_ci} 158662306a36Sopenharmony_ci 158762306a36Sopenharmony_cistatic void ib_generic_event_task(struct work_struct *_work) 158862306a36Sopenharmony_ci{ 158962306a36Sopenharmony_ci struct ib_update_work *work = 159062306a36Sopenharmony_ci container_of(_work, struct ib_update_work, work); 159162306a36Sopenharmony_ci 159262306a36Sopenharmony_ci ib_dispatch_event_clients(&work->event); 159362306a36Sopenharmony_ci kfree(work); 159462306a36Sopenharmony_ci} 159562306a36Sopenharmony_ci 159662306a36Sopenharmony_cistatic bool is_cache_update_event(const struct ib_event *event) 159762306a36Sopenharmony_ci{ 159862306a36Sopenharmony_ci return (event->event == IB_EVENT_PORT_ERR || 159962306a36Sopenharmony_ci event->event == IB_EVENT_PORT_ACTIVE || 160062306a36Sopenharmony_ci event->event == IB_EVENT_LID_CHANGE || 160162306a36Sopenharmony_ci event->event == IB_EVENT_PKEY_CHANGE || 160262306a36Sopenharmony_ci event->event == IB_EVENT_CLIENT_REREGISTER || 160362306a36Sopenharmony_ci event->event == IB_EVENT_GID_CHANGE); 160462306a36Sopenharmony_ci} 160562306a36Sopenharmony_ci 160662306a36Sopenharmony_ci/** 160762306a36Sopenharmony_ci * ib_dispatch_event - Dispatch an asynchronous event 160862306a36Sopenharmony_ci * @event:Event to dispatch 160962306a36Sopenharmony_ci * 161062306a36Sopenharmony_ci * Low-level drivers must call ib_dispatch_event() to dispatch the 161162306a36Sopenharmony_ci * event to all registered event handlers when an asynchronous event 161262306a36Sopenharmony_ci * occurs. 161362306a36Sopenharmony_ci */ 161462306a36Sopenharmony_civoid ib_dispatch_event(const struct ib_event *event) 161562306a36Sopenharmony_ci{ 161662306a36Sopenharmony_ci struct ib_update_work *work; 161762306a36Sopenharmony_ci 161862306a36Sopenharmony_ci work = kzalloc(sizeof(*work), GFP_ATOMIC); 161962306a36Sopenharmony_ci if (!work) 162062306a36Sopenharmony_ci return; 162162306a36Sopenharmony_ci 162262306a36Sopenharmony_ci if (is_cache_update_event(event)) 162362306a36Sopenharmony_ci INIT_WORK(&work->work, ib_cache_event_task); 162462306a36Sopenharmony_ci else 162562306a36Sopenharmony_ci INIT_WORK(&work->work, ib_generic_event_task); 162662306a36Sopenharmony_ci 162762306a36Sopenharmony_ci work->event = *event; 162862306a36Sopenharmony_ci if (event->event == IB_EVENT_PKEY_CHANGE || 162962306a36Sopenharmony_ci event->event == IB_EVENT_GID_CHANGE) 163062306a36Sopenharmony_ci work->enforce_security = true; 163162306a36Sopenharmony_ci 163262306a36Sopenharmony_ci queue_work(ib_wq, &work->work); 163362306a36Sopenharmony_ci} 163462306a36Sopenharmony_ciEXPORT_SYMBOL(ib_dispatch_event); 163562306a36Sopenharmony_ci 163662306a36Sopenharmony_ciint ib_cache_setup_one(struct ib_device *device) 163762306a36Sopenharmony_ci{ 163862306a36Sopenharmony_ci u32 p; 163962306a36Sopenharmony_ci int err; 164062306a36Sopenharmony_ci 164162306a36Sopenharmony_ci err = gid_table_setup_one(device); 164262306a36Sopenharmony_ci if (err) 164362306a36Sopenharmony_ci return err; 164462306a36Sopenharmony_ci 164562306a36Sopenharmony_ci rdma_for_each_port (device, p) { 164662306a36Sopenharmony_ci err = ib_cache_update(device, p, true, true, true); 164762306a36Sopenharmony_ci if (err) 164862306a36Sopenharmony_ci return err; 164962306a36Sopenharmony_ci } 165062306a36Sopenharmony_ci 165162306a36Sopenharmony_ci return 0; 165262306a36Sopenharmony_ci} 165362306a36Sopenharmony_ci 165462306a36Sopenharmony_civoid ib_cache_release_one(struct ib_device *device) 165562306a36Sopenharmony_ci{ 165662306a36Sopenharmony_ci u32 p; 165762306a36Sopenharmony_ci 165862306a36Sopenharmony_ci /* 165962306a36Sopenharmony_ci * The release function frees all the cache elements. 166062306a36Sopenharmony_ci * This function should be called as part of freeing 166162306a36Sopenharmony_ci * all the device's resources when the cache could no 166262306a36Sopenharmony_ci * longer be accessed. 166362306a36Sopenharmony_ci */ 166462306a36Sopenharmony_ci rdma_for_each_port (device, p) 166562306a36Sopenharmony_ci kfree(device->port_data[p].cache.pkey); 166662306a36Sopenharmony_ci 166762306a36Sopenharmony_ci gid_table_release_one(device); 166862306a36Sopenharmony_ci} 166962306a36Sopenharmony_ci 167062306a36Sopenharmony_civoid ib_cache_cleanup_one(struct ib_device *device) 167162306a36Sopenharmony_ci{ 167262306a36Sopenharmony_ci /* The cleanup function waits for all in-progress workqueue 167362306a36Sopenharmony_ci * elements and cleans up the GID cache. This function should be 167462306a36Sopenharmony_ci * called after the device was removed from the devices list and 167562306a36Sopenharmony_ci * all clients were removed, so the cache exists but is 167662306a36Sopenharmony_ci * non-functional and shouldn't be updated anymore. 167762306a36Sopenharmony_ci */ 167862306a36Sopenharmony_ci flush_workqueue(ib_wq); 167962306a36Sopenharmony_ci gid_table_cleanup_one(device); 168062306a36Sopenharmony_ci 168162306a36Sopenharmony_ci /* 168262306a36Sopenharmony_ci * Flush the wq second time for any pending GID delete work. 168362306a36Sopenharmony_ci */ 168462306a36Sopenharmony_ci flush_workqueue(ib_wq); 168562306a36Sopenharmony_ci} 1686