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

📄 cm.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 5 页
字号:
/* * Copyright (c) 2004, 2005 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 2821 2005-07-08 17:07:28Z sean.hefty $ */#include <linux/dma-mapping.h>#include <linux/err.h>#include <linux/idr.h>#include <linux/interrupt.h>#include <linux/pci.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;	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;	__be64 ca_guid;	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 packet_life_time;};struct cm_work {	struct work_struct 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 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;	wait_queue_head_t wait;	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;	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;	u8 private_data_len;	u8 max_cm_retries;	u8 peer_to_peer;	u8 responder_resources;	u8 initiator_depth;	u8 local_ack_timeout;	u8 retry_count;	u8 rnr_retry_count;	u8 service_timeout;	struct list_head work_list;	atomic_t work_count;};static void cm_work_handler(void *data);static inline void cm_deref_id(struct cm_id_private *cm_id_priv){	if (atomic_dec_and_test(&cm_id_priv->refcount))		wake_up(&cm_id_priv->wait);}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 = kmalloc(private_data_len, GFP_KERNEL);	if (!data)		return ERR_PTR(-ENOMEM);	memcpy(data, private_data, private_data_len);	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_set_ah_attr(struct ib_ah_attr *ah_attr, u8 port_num,			   u16 dlid, u8 sl, u16 src_path_bits){	memset(ah_attr, 0, sizeof ah_attr);	ah_attr->dlid = dlid;	ah_attr->sl = sl;	ah_attr->src_path_bits = src_path_bits;	ah_attr->port_num = port_num;}static void cm_init_av_for_response(struct cm_port *port,				    struct ib_wc *wc, struct cm_av *av){	av->port = port;	av->pkey_index = wc->pkey_index;	cm_set_ah_attr(&av->ah_attr, port->port_num, wc->slid,		       wc->sl, wc->dlid_path_bits);}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;	cm_set_ah_attr(&av->ah_attr, av->port->port_num,		       be16_to_cpu(path->dlid), path->sl,		       be16_to_cpu(path->slid) & 0x7F);	av->packet_life_time = path->packet_life_time;	return 0;}static int cm_alloc_id(struct cm_id_private *cm_id_priv){	unsigned long flags;	int ret;	do {		spin_lock_irqsave(&cm.lock, flags);		ret = idr_get_new_above(&cm.local_id_table, cm_id_priv, 1,					(__force int *) &cm_id_priv->id.local_id);		spin_unlock_irqrestore(&cm.lock, flags);	} while( (ret == -EAGAIN) && idr_pre_get(&cm.local_id_table, GFP_KERNEL) );	return ret;}static void cm_free_id(__be32 local_id){	unsigned long flags;	spin_lock_irqsave(&cm.lock, flags);	idr_remove(&cm.local_id_table, (__force int) local_id);	spin_unlock_irqrestore(&cm.lock, flags);}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);	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;	unsigned long flags;	spin_lock_irqsave(&cm.lock, flags);	cm_id_priv = cm_get_id(local_id, remote_id);	spin_unlock_irqrestore(&cm.lock, flags);	return cm_id_priv;}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;	while (*link) {		parent = *link;		cur_cm_id_priv = rb_entry(parent, struct cm_id_private,					  service_node);		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))			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			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){	struct rb_node *node = cm.listen_service_table.rb_node;	struct cm_id_private *cm_id_priv;	while (node) {		cm_id_priv = rb_entry(node, struct cm_id_private, service_node);		if ((cm_id_priv->id.service_mask & service_id) ==		     cm_id_priv->id.service_id &&		    (cm_id_priv->id.device == device))			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)			node = node->rb_left;		else			node = node->rb_right;	}	return NULL;}static struct cm_timewait_info * cm_insert_remote_id(struct cm_timewait_info						     *timewait_info){	struct rb_node **link = &cm.remote_id_table.rb_node;	struct rb_node *parent = NULL;	struct cm_timewait_info *cur_timewait_info;	__be64 remote_ca_guid = timewait_info->remote_ca_guid;	__be32 remote_id = timewait_info->work.remote_id;	while (*link) {		parent = *link;		cur_timewait_info = rb_entry(parent, struct cm_timewait_info,					     remote_id_node);		if (remote_id < cur_timewait_info->work.remote_id)			link = &(*link)->rb_left;		else if (remote_id > cur_timewait_info->work.remote_id)			link = &(*link)->rb_right;		else if (remote_ca_guid < cur_timewait_info->remote_ca_guid)			link = &(*link)->rb_left;		else if (remote_ca_guid > cur_timewait_info->remote_ca_guid)			link = &(*link)->rb_right;		else			return cur_timewait_info;	}	timewait_info->inserted_remote_id = 1;	rb_link_node(&timewait_info->remote_id_node, parent, link);	rb_insert_color(&timewait_info->remote_id_node, &cm.remote_id_table);	return NULL;}static struct cm_timewait_info * cm_find_remote_id(__be64 remote_ca_guid,						   __be32 remote_id){	struct rb_node *node = cm.remote_id_table.rb_node;	struct cm_timewait_info *timewait_info;

⌨️ 快捷键说明

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