⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 cm.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
/* * Copyright (c) 2004-2006 Intel Corporation.  All rights reserved. * Copyright (c) 2004 Topspin Corporation.  All rights reserved. * Copyright (c) 2004, 2005 Voltaire Corporation.  All rights reserved. * Copyright (c) 2005 Sun Microsystems, 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. * * $Id: cm.c 4311 2005-12-05 18:42:01Z sean.hefty $ */#include <linux/completion.h>#include <linux/dma-mapping.h>#include <linux/err.h>#include <linux/idr.h>#include <linux/interrupt.h>#include <linux/random.h>#include <linux/rbtree.h>#include <linux/spinlock.h>#include <linux/workqueue.h>#include <rdma/ib_cache.h>#include <rdma/ib_cm.h>#include "cm_msgs.h"MODULE_AUTHOR("Sean Hefty");MODULE_DESCRIPTION("InfiniBand CM");MODULE_LICENSE("Dual BSD/GPL");static void cm_add_one(struct ib_device *device);static void cm_remove_one(struct ib_device *device);static struct ib_client cm_client = {	.name   = "cm",	.add    = cm_add_one,	.remove = cm_remove_one};static struct ib_cm {	spinlock_t lock;	struct list_head device_list;	rwlock_t device_lock;	struct rb_root listen_service_table;	u64 listen_service_id;	/* struct rb_root peer_service_table; todo: fix peer to peer */	struct rb_root remote_qp_table;	struct rb_root remote_id_table;	struct rb_root remote_sidr_table;	struct idr local_id_table;	__be32 random_id_operand;	struct list_head timewait_list;	struct workqueue_struct *wq;} cm;struct cm_port {	struct cm_device *cm_dev;	struct ib_mad_agent *mad_agent;	u8 port_num;};struct cm_device {	struct list_head list;	struct ib_device *device;	u8 ack_delay;	struct cm_port port[0];};struct cm_av {	struct cm_port *port;	union ib_gid dgid;	struct ib_ah_attr ah_attr;	u16 pkey_index;	u8 timeout;};struct cm_work {	struct delayed_work work;	struct list_head list;	struct cm_port *port;	struct ib_mad_recv_wc *mad_recv_wc;	/* Received MADs */	__be32 local_id;			/* Established / timewait */	__be32 remote_id;	struct ib_cm_event cm_event;	struct ib_sa_path_rec path[0];};struct cm_timewait_info {	struct cm_work work;			/* Must be first. */	struct list_head list;	struct rb_node remote_qp_node;	struct rb_node remote_id_node;	__be64 remote_ca_guid;	__be32 remote_qpn;	u8 inserted_remote_qp;	u8 inserted_remote_id;};struct cm_id_private {	struct ib_cm_id	id;	struct rb_node service_node;	struct rb_node sidr_id_node;	spinlock_t lock;	/* Do not acquire inside cm.lock */	struct completion comp;	atomic_t refcount;	struct ib_mad_send_buf *msg;	struct cm_timewait_info *timewait_info;	/* todo: use alternate port on send failure */	struct cm_av av;	struct cm_av alt_av;	struct ib_cm_compare_data *compare_data;	void *private_data;	__be64 tid;	__be32 local_qpn;	__be32 remote_qpn;	enum ib_qp_type qp_type;	__be32 sq_psn;	__be32 rq_psn;	int timeout_ms;	enum ib_mtu path_mtu;	__be16 pkey;	u8 private_data_len;	u8 max_cm_retries;	u8 peer_to_peer;	u8 responder_resources;	u8 initiator_depth;	u8 retry_count;	u8 rnr_retry_count;	u8 service_timeout;	u8 target_ack_delay;	struct list_head work_list;	atomic_t work_count;};static void cm_work_handler(struct work_struct *work);static inline void cm_deref_id(struct cm_id_private *cm_id_priv){	if (atomic_dec_and_test(&cm_id_priv->refcount))		complete(&cm_id_priv->comp);}static int cm_alloc_msg(struct cm_id_private *cm_id_priv,			struct ib_mad_send_buf **msg){	struct ib_mad_agent *mad_agent;	struct ib_mad_send_buf *m;	struct ib_ah *ah;	mad_agent = cm_id_priv->av.port->mad_agent;	ah = ib_create_ah(mad_agent->qp->pd, &cm_id_priv->av.ah_attr);	if (IS_ERR(ah))		return PTR_ERR(ah);	m = ib_create_send_mad(mad_agent, cm_id_priv->id.remote_cm_qpn,			       cm_id_priv->av.pkey_index,			       0, IB_MGMT_MAD_HDR, IB_MGMT_MAD_DATA,			       GFP_ATOMIC);	if (IS_ERR(m)) {		ib_destroy_ah(ah);		return PTR_ERR(m);	}	/* Timeout set by caller if response is expected. */	m->ah = ah;	m->retries = cm_id_priv->max_cm_retries;	atomic_inc(&cm_id_priv->refcount);	m->context[0] = cm_id_priv;	*msg = m;	return 0;}static int cm_alloc_response_msg(struct cm_port *port,				 struct ib_mad_recv_wc *mad_recv_wc,				 struct ib_mad_send_buf **msg){	struct ib_mad_send_buf *m;	struct ib_ah *ah;	ah = ib_create_ah_from_wc(port->mad_agent->qp->pd, mad_recv_wc->wc,				  mad_recv_wc->recv_buf.grh, port->port_num);	if (IS_ERR(ah))		return PTR_ERR(ah);	m = ib_create_send_mad(port->mad_agent, 1, mad_recv_wc->wc->pkey_index,			       0, IB_MGMT_MAD_HDR, IB_MGMT_MAD_DATA,			       GFP_ATOMIC);	if (IS_ERR(m)) {		ib_destroy_ah(ah);		return PTR_ERR(m);	}	m->ah = ah;	*msg = m;	return 0;}static void cm_free_msg(struct ib_mad_send_buf *msg){	ib_destroy_ah(msg->ah);	if (msg->context[0])		cm_deref_id(msg->context[0]);	ib_free_send_mad(msg);}static void * cm_copy_private_data(const void *private_data,				   u8 private_data_len){	void *data;	if (!private_data || !private_data_len)		return NULL;	data = kmemdup(private_data, private_data_len, GFP_KERNEL);	if (!data)		return ERR_PTR(-ENOMEM);	return data;}static void cm_set_private_data(struct cm_id_private *cm_id_priv,				 void *private_data, u8 private_data_len){	if (cm_id_priv->private_data && cm_id_priv->private_data_len)		kfree(cm_id_priv->private_data);	cm_id_priv->private_data = private_data;	cm_id_priv->private_data_len = private_data_len;}static void cm_init_av_for_response(struct cm_port *port, struct ib_wc *wc,				    struct ib_grh *grh, struct cm_av *av){	av->port = port;	av->pkey_index = wc->pkey_index;	ib_init_ah_from_wc(port->cm_dev->device, port->port_num, wc,			   grh, &av->ah_attr);}static int cm_init_av_by_path(struct ib_sa_path_rec *path, struct cm_av *av){	struct cm_device *cm_dev;	struct cm_port *port = NULL;	unsigned long flags;	int ret;	u8 p;	read_lock_irqsave(&cm.device_lock, flags);	list_for_each_entry(cm_dev, &cm.device_list, list) {		if (!ib_find_cached_gid(cm_dev->device, &path->sgid,					&p, NULL)) {			port = &cm_dev->port[p-1];			break;		}	}	read_unlock_irqrestore(&cm.device_lock, flags);	if (!port)		return -EINVAL;	ret = ib_find_cached_pkey(cm_dev->device, port->port_num,				  be16_to_cpu(path->pkey), &av->pkey_index);	if (ret)		return ret;	av->port = port;	ib_init_ah_from_path(cm_dev->device, port->port_num, path,			     &av->ah_attr);	av->timeout = path->packet_life_time + 1;	return 0;}static int cm_alloc_id(struct cm_id_private *cm_id_priv){	unsigned long flags;	int ret, id;	static int next_id;	do {		spin_lock_irqsave(&cm.lock, flags);		ret = idr_get_new_above(&cm.local_id_table, cm_id_priv,					next_id, &id);		if (!ret)			next_id = ((unsigned) id + 1) & MAX_ID_MASK;		spin_unlock_irqrestore(&cm.lock, flags);	} while( (ret == -EAGAIN) && idr_pre_get(&cm.local_id_table, GFP_KERNEL) );	cm_id_priv->id.local_id = (__force __be32) (id ^ cm.random_id_operand);	return ret;}static void cm_free_id(__be32 local_id){	spin_lock_irq(&cm.lock);	idr_remove(&cm.local_id_table,		   (__force int) (local_id ^ cm.random_id_operand));	spin_unlock_irq(&cm.lock);}static struct cm_id_private * cm_get_id(__be32 local_id, __be32 remote_id){	struct cm_id_private *cm_id_priv;	cm_id_priv = idr_find(&cm.local_id_table,			      (__force int) (local_id ^ cm.random_id_operand));	if (cm_id_priv) {		if (cm_id_priv->id.remote_id == remote_id)			atomic_inc(&cm_id_priv->refcount);		else			cm_id_priv = NULL;	}	return cm_id_priv;}static struct cm_id_private * cm_acquire_id(__be32 local_id, __be32 remote_id){	struct cm_id_private *cm_id_priv;	spin_lock_irq(&cm.lock);	cm_id_priv = cm_get_id(local_id, remote_id);	spin_unlock_irq(&cm.lock);	return cm_id_priv;}static void cm_mask_copy(u8 *dst, u8 *src, u8 *mask){	int i;	for (i = 0; i < IB_CM_COMPARE_SIZE / sizeof(unsigned long); i++)		((unsigned long *) dst)[i] = ((unsigned long *) src)[i] &					     ((unsigned long *) mask)[i];}static int cm_compare_data(struct ib_cm_compare_data *src_data,			   struct ib_cm_compare_data *dst_data){	u8 src[IB_CM_COMPARE_SIZE];	u8 dst[IB_CM_COMPARE_SIZE];	if (!src_data || !dst_data)		return 0;	cm_mask_copy(src, src_data->data, dst_data->mask);	cm_mask_copy(dst, dst_data->data, src_data->mask);	return memcmp(src, dst, IB_CM_COMPARE_SIZE);}static int cm_compare_private_data(u8 *private_data,				   struct ib_cm_compare_data *dst_data){	u8 src[IB_CM_COMPARE_SIZE];	if (!dst_data)		return 0;	cm_mask_copy(src, private_data, dst_data->mask);	return memcmp(src, dst_data->data, IB_CM_COMPARE_SIZE);}static struct cm_id_private * cm_insert_listen(struct cm_id_private *cm_id_priv){	struct rb_node **link = &cm.listen_service_table.rb_node;	struct rb_node *parent = NULL;	struct cm_id_private *cur_cm_id_priv;	__be64 service_id = cm_id_priv->id.service_id;	__be64 service_mask = cm_id_priv->id.service_mask;	int data_cmp;	while (*link) {		parent = *link;		cur_cm_id_priv = rb_entry(parent, struct cm_id_private,					  service_node);		data_cmp = cm_compare_data(cm_id_priv->compare_data,					   cur_cm_id_priv->compare_data);		if ((cur_cm_id_priv->id.service_mask & service_id) ==		    (service_mask & cur_cm_id_priv->id.service_id) &&		    (cm_id_priv->id.device == cur_cm_id_priv->id.device) &&		    !data_cmp)			return cur_cm_id_priv;		if (cm_id_priv->id.device < cur_cm_id_priv->id.device)			link = &(*link)->rb_left;		else if (cm_id_priv->id.device > cur_cm_id_priv->id.device)			link = &(*link)->rb_right;		else if (service_id < cur_cm_id_priv->id.service_id)			link = &(*link)->rb_left;		else if (service_id > cur_cm_id_priv->id.service_id)			link = &(*link)->rb_right;		else if (data_cmp < 0)			link = &(*link)->rb_left;		else			link = &(*link)->rb_right;	}	rb_link_node(&cm_id_priv->service_node, parent, link);	rb_insert_color(&cm_id_priv->service_node, &cm.listen_service_table);	return NULL;}static struct cm_id_private * cm_find_listen(struct ib_device *device,					     __be64 service_id,					     u8 *private_data){	struct rb_node *node = cm.listen_service_table.rb_node;	struct cm_id_private *cm_id_priv;	int data_cmp;	while (node) {		cm_id_priv = rb_entry(node, struct cm_id_private, service_node);		data_cmp = cm_compare_private_data(private_data,						   cm_id_priv->compare_data);		if ((cm_id_priv->id.service_mask & service_id) ==		     cm_id_priv->id.service_id &&		    (cm_id_priv->id.device == device) && !data_cmp)			return cm_id_priv;		if (device < cm_id_priv->id.device)			node = node->rb_left;		else if (device > cm_id_priv->id.device)			node = node->rb_right;		else if (service_id < cm_id_priv->id.service_id)

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -