1657 lines · 42.5 KB · C
RawDownload
/* * Copyright (c) 2004 Topspin Communications.  All rights reserved. * Copyright (c) 2005 Intel Corporation. All rights reserved. * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved. * Copyright (c) 2005 Voltaire, Inc. All rights reserved. * * This software is available to you under a choice of one of two * licenses.  You may choose to be licensed under the terms of the GNU * General Public License (GPL) Version 2, available from the file * COPYING in the main directory of this source tree, or the * OpenIB.org BSD license below: * *     Redistribution and use in source and binary forms, with or *     without modification, are permitted provided that the following *     conditions are met: * *      - Redistributions of source code must retain the above *        copyright notice, this list of conditions and the following *        disclaimer. * *      - Redistributions in binary form must reproduce the above *        copyright notice, this list of conditions and the following *        disclaimer in the documentation and/or other materials *        provided with the distribution. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ #include <linux/if_vlan.h>#include <linux/errno.h>#include <linux/slab.h>#include <linux/workqueue.h>#include <linux/netdevice.h>#include <net/addrconf.h> #include <rdma/ib_cache.h> #include "core_priv.h" struct ib_pkey_cache {	int             table_len;	u16             table[] __counted_by(table_len);}; struct ib_update_work {	struct work_struct work;	struct ib_event event;	bool enforce_security;}; union ib_gid zgid;EXPORT_SYMBOL(zgid); enum gid_attr_find_mask {	GID_ATTR_FIND_MASK_GID          = 1UL << 0,	GID_ATTR_FIND_MASK_NETDEV	= 1UL << 1,	GID_ATTR_FIND_MASK_DEFAULT	= 1UL << 2,	GID_ATTR_FIND_MASK_GID_TYPE	= 1UL << 3,}; enum gid_table_entry_state {	GID_TABLE_ENTRY_INVALID		= 1,	GID_TABLE_ENTRY_VALID		= 2,	/*	 * Indicates that entry is pending to be removed, there may	 * be active users of this GID entry.	 * When last user of the GID entry releases reference to it,	 * GID entry is detached from the table.	 */	GID_TABLE_ENTRY_PENDING_DEL	= 3,}; struct roce_gid_ndev_storage {	struct rcu_head rcu_head;	struct net_device *ndev;}; struct ib_gid_table_entry {	struct kref			kref;	struct work_struct		del_work;	struct ib_gid_attr		attr;	void				*context;	/* Store the ndev pointer to release reference later on in	 * call_rcu context because by that time gid_table_entry	 * and attr might be already freed. So keep a copy of it.	 * ndev_storage is freed by rcu callback.	 */	struct roce_gid_ndev_storage	*ndev_storage;	enum gid_table_entry_state	state;}; struct ib_gid_table {	int				sz;	/* In RoCE, adding a GID to the table requires:	 * (a) Find if this GID is already exists.	 * (b) Find a free space.	 * (c) Write the new GID	 *	 * Delete requires different set of operations:	 * (a) Find the GID	 * (b) Delete it.	 *	 **/	/* Any writer to data_vec must hold this lock and the write side of	 * rwlock. Readers must hold only rwlock. All writers must be in a	 * sleepable context.	 */	struct mutex			lock;	/* rwlock protects data_vec[ix]->state and entry pointer.	 */	rwlock_t			rwlock;	/* bit field, each bit indicates the index of default GID */	u32				default_gid_indices;	struct ib_gid_table_entry	*data_vec[] __counted_by(sz);}; static void dispatch_gid_change_event(struct ib_device *ib_dev, u32 port){	struct ib_event event; 	event.device		= ib_dev;	event.element.port_num	= port;	event.event		= IB_EVENT_GID_CHANGE; 	ib_dispatch_event_clients(&event);} static const char * const gid_type_str[] = {	/* IB/RoCE v1 value is set for IB_GID_TYPE_IB and IB_GID_TYPE_ROCE for	 * user space compatibility reasons.	 */	[IB_GID_TYPE_IB]	= "IB/RoCE v1",	[IB_GID_TYPE_ROCE]	= "IB/RoCE v1",	[IB_GID_TYPE_ROCE_UDP_ENCAP]	= "RoCE v2",}; const char *ib_cache_gid_type_str(enum ib_gid_type gid_type){	if (gid_type < ARRAY_SIZE(gid_type_str) && gid_type_str[gid_type])		return gid_type_str[gid_type]; 	return "Invalid GID type";}EXPORT_SYMBOL(ib_cache_gid_type_str); /** rdma_is_zero_gid - Check if given GID is zero or not. * @gid:	GID to check * Returns true if given GID is zero, returns false otherwise. */bool rdma_is_zero_gid(const union ib_gid *gid){	return !memcmp(gid, &zgid, sizeof(*gid));}EXPORT_SYMBOL(rdma_is_zero_gid); /** is_gid_index_default - Check if a given index belongs to * reserved default GIDs or not. * @table:	GID table pointer * @index:	Index to check in GID table * Returns true if index is one of the reserved default GID index otherwise * returns false. */static bool is_gid_index_default(const struct ib_gid_table *table,				 unsigned int index){	return index < 32 && (BIT(index) & table->default_gid_indices);} int ib_cache_gid_parse_type_str(const char *buf){	unsigned int i;	size_t len;	int err = -EINVAL; 	len = strlen(buf);	if (len == 0)		return -EINVAL; 	if (buf[len - 1] == '\n')		len--; 	for (i = 0; i < ARRAY_SIZE(gid_type_str); ++i)		if (gid_type_str[i] && !strncmp(buf, gid_type_str[i], len) &&		    len == strlen(gid_type_str[i])) {			err = i;			break;		} 	return err;}EXPORT_SYMBOL(ib_cache_gid_parse_type_str); static struct ib_gid_table *rdma_gid_table(struct ib_device *device, u32 port){	return device->port_data[port].cache.gid;} static bool is_gid_entry_free(const struct ib_gid_table_entry *entry){	return !entry;} static bool is_gid_entry_valid(const struct ib_gid_table_entry *entry){	return entry && entry->state == GID_TABLE_ENTRY_VALID;} static void schedule_free_gid(struct kref *kref){	struct ib_gid_table_entry *entry =			container_of(kref, struct ib_gid_table_entry, kref); 	queue_work(ib_wq, &entry->del_work);} static void put_gid_ndev(struct rcu_head *head){	struct roce_gid_ndev_storage *storage =		container_of(head, struct roce_gid_ndev_storage, rcu_head); 	WARN_ON(!storage->ndev);	/* At this point its safe to release netdev reference,	 * as all callers working on gid_attr->ndev are done	 * using this netdev.	 */	dev_put(storage->ndev);	kfree(storage);} static void free_gid_entry_locked(struct ib_gid_table_entry *entry){	struct ib_device *device = entry->attr.device;	u32 port_num = entry->attr.port_num;	struct ib_gid_table *table = rdma_gid_table(device, port_num); 	dev_dbg(&device->dev, "%s port=%u index=%u gid %pI6\n", __func__,		port_num, entry->attr.index, entry->attr.gid.raw); 	write_lock_irq(&table->rwlock); 	/*	 * The only way to avoid overwriting NULL in table is	 * by comparing if it is same entry in table or not!	 * If new entry in table is added by the time we free here,	 * don't overwrite the table entry.	 */	if (entry == table->data_vec[entry->attr.index])		table->data_vec[entry->attr.index] = NULL;	/* Now this index is ready to be allocated */	write_unlock_irq(&table->rwlock); 	if (entry->ndev_storage)		call_rcu(&entry->ndev_storage->rcu_head, put_gid_ndev);	kfree(entry);} static void free_gid_entry(struct kref *kref){	struct ib_gid_table_entry *entry =			container_of(kref, struct ib_gid_table_entry, kref); 	free_gid_entry_locked(entry);} /** * free_gid_work - Release reference to the GID entry * @work: Work structure to refer to GID entry which needs to be * deleted. * * free_gid_work() frees the entry from the HCA's hardware table * if provider supports it. It releases reference to netdevice. */static void free_gid_work(struct work_struct *work){	struct ib_gid_table_entry *entry =		container_of(work, struct ib_gid_table_entry, del_work);	struct ib_device *device = entry->attr.device;	u32 port_num = entry->attr.port_num;	struct ib_gid_table *table = rdma_gid_table(device, port_num); 	mutex_lock(&table->lock);	free_gid_entry_locked(entry);	mutex_unlock(&table->lock);} static struct ib_gid_table_entry *alloc_gid_entry(const struct ib_gid_attr *attr){	struct ib_gid_table_entry *entry;	struct net_device *ndev; 	entry = kzalloc_obj(*entry);	if (!entry)		return NULL; 	ndev = rcu_dereference_protected(attr->ndev, 1);	if (ndev) {		entry->ndev_storage = kzalloc_obj(*entry->ndev_storage);		if (!entry->ndev_storage) {			kfree(entry);			return NULL;		}		dev_hold(ndev);		entry->ndev_storage->ndev = ndev;	}	kref_init(&entry->kref);	memcpy(&entry->attr, attr, sizeof(*attr));	INIT_WORK(&entry->del_work, free_gid_work);	entry->state = GID_TABLE_ENTRY_INVALID;	return entry;} static void store_gid_entry(struct ib_gid_table *table,			    struct ib_gid_table_entry *entry){	entry->state = GID_TABLE_ENTRY_VALID; 	dev_dbg(&entry->attr.device->dev, "%s port=%u index=%u gid %pI6\n",		__func__, entry->attr.port_num, entry->attr.index,		entry->attr.gid.raw); 	lockdep_assert_held(&table->lock);	write_lock_irq(&table->rwlock);	table->data_vec[entry->attr.index] = entry;	write_unlock_irq(&table->rwlock);} static void get_gid_entry(struct ib_gid_table_entry *entry){	kref_get(&entry->kref);} static void put_gid_entry(struct ib_gid_table_entry *entry){	kref_put(&entry->kref, schedule_free_gid);} static void put_gid_entry_locked(struct ib_gid_table_entry *entry){	kref_put(&entry->kref, free_gid_entry);} static int add_roce_gid(struct ib_gid_table_entry *entry){	const struct ib_gid_attr *attr = &entry->attr;	int ret; 	if (!attr->ndev) {		dev_err(&attr->device->dev, "%s NULL netdev port=%u index=%u\n",			__func__, attr->port_num, attr->index);		return -EINVAL;	}	if (rdma_cap_roce_gid_table(attr->device, attr->port_num)) {		ret = attr->device->ops.add_gid(attr, &entry->context);		if (ret) {			dev_err(&attr->device->dev,				"%s GID add failed port=%u index=%u\n",				__func__, attr->port_num, attr->index);			return ret;		}	}	return 0;} /** * del_gid - Delete GID table entry * * @ib_dev:	IB device whose GID entry to be deleted * @port:	Port number of the IB device * @table:	GID table of the IB device for a port * @ix:		GID entry index to delete * */static void del_gid(struct ib_device *ib_dev, u32 port,		    struct ib_gid_table *table, int ix){	struct roce_gid_ndev_storage *ndev_storage;	struct ib_gid_table_entry *entry; 	lockdep_assert_held(&table->lock); 	dev_dbg(&ib_dev->dev, "%s port=%u index=%d gid %pI6\n", __func__, port,		ix, table->data_vec[ix]->attr.gid.raw); 	write_lock_irq(&table->rwlock);	entry = table->data_vec[ix];	entry->state = GID_TABLE_ENTRY_PENDING_DEL;	/*	 * For non RoCE protocol, GID entry slot is ready to use.	 */	if (!rdma_protocol_roce(ib_dev, port))		table->data_vec[ix] = NULL;	write_unlock_irq(&table->rwlock); 	if (rdma_cap_roce_gid_table(ib_dev, port))		ib_dev->ops.del_gid(&entry->attr, &entry->context); 	ndev_storage = entry->ndev_storage;	if (ndev_storage) {		entry->ndev_storage = NULL;		rcu_assign_pointer(entry->attr.ndev, NULL);		call_rcu(&ndev_storage->rcu_head, put_gid_ndev);	} 	put_gid_entry_locked(entry);} /** * add_modify_gid - Add or modify GID table entry * * @table:	GID table in which GID to be added or modified * @attr:	Attributes of the GID * * Returns 0 on success or appropriate error code. It accepts zero * GID addition for non RoCE ports for HCA's who report them as valid * GID. However such zero GIDs are not added to the cache. */static int add_modify_gid(struct ib_gid_table *table,			  const struct ib_gid_attr *attr){	struct ib_gid_table_entry *entry;	int ret = 0; 	/*	 * Invalidate any old entry in the table to make it safe to write to	 * this index.	 */	if (is_gid_entry_valid(table->data_vec[attr->index]))		del_gid(attr->device, attr->port_num, table, attr->index); 	/*	 * Some HCA's report multiple GID entries with only one valid GID, and	 * leave other unused entries as the zero GID. Convert zero GIDs to	 * empty table entries instead of storing them.	 */	if (rdma_is_zero_gid(&attr->gid))		return 0; 	entry = alloc_gid_entry(attr);	if (!entry)		return -ENOMEM; 	if (rdma_protocol_roce(attr->device, attr->port_num)) {		ret = add_roce_gid(entry);		if (ret)			goto done;	} 	store_gid_entry(table, entry);	return 0; done:	put_gid_entry(entry);	return ret;} /* rwlock should be read locked, or lock should be held */static int find_gid(struct ib_gid_table *table, const union ib_gid *gid,		    const struct ib_gid_attr *val, bool default_gid,		    unsigned long mask, int *pempty){	int i = 0;	int found = -1;	int empty = pempty ? -1 : 0; 	while (i < table->sz && (found < 0 || empty < 0)) {		struct ib_gid_table_entry *data = table->data_vec[i];		struct ib_gid_attr *attr;		int curr_index = i; 		i++; 		/* find_gid() is used during GID addition where it is expected		 * to return a free entry slot which is not duplicate.		 * Free entry slot is requested and returned if pempty is set,		 * so lookup free slot only if requested.		 */		if (pempty && empty < 0) {			if (is_gid_entry_free(data) &&			    default_gid ==				is_gid_index_default(table, curr_index)) {				/*				 * Found an invalid (free) entry; allocate it.				 * If default GID is requested, then our				 * found slot must be one of the DEFAULT				 * reserved slots or we fail.				 * This ensures that only DEFAULT reserved				 * slots are used for default property GIDs.				 */				empty = curr_index;			}		} 

Lines 1–500 of 1657.