*
* $Id: cm.c 2821 2005-07-08 17:07:28Z sean.hefty $
*/
+
+#include <linux/completion.h>
#include <linux/dma-mapping.h>
#include <linux/err.h>
#include <linux/idr.h>
struct rb_node service_node;
struct rb_node sidr_id_node;
- spinlock_t lock;
- wait_queue_head_t wait;
+ spinlock_t lock; /* Do not acquire inside cm.lock */
+ struct completion comp;
atomic_t refcount;
struct ib_mad_send_buf *msg;
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);
+ complete(&cm_id_priv->comp);
}
static int cm_alloc_msg(struct cm_id_private *cm_id_priv,
goto error;
spin_lock_init(&cm_id_priv->lock);
- init_waitqueue_head(&cm_id_priv->wait);
+ init_completion(&cm_id_priv->comp);
INIT_LIST_HEAD(&cm_id_priv->work_list);
atomic_set(&cm_id_priv->work_count, -1);
atomic_set(&cm_id_priv->refcount, 1);
}
cm_free_id(cm_id->local_id);
- atomic_dec(&cm_id_priv->refcount);
- wait_event(cm_id_priv->wait, !atomic_read(&cm_id_priv->refcount));
+ cm_deref_id(cm_id_priv);
+ wait_for_completion(&cm_id_priv->comp);
while ((work = cm_dequeue_work(cm_id_priv)) != NULL)
cm_free_work(work);
if (cm_id_priv->private_data && cm_id_priv->private_data_len)
param->private_data_len);
}
-static inline int cm_validate_req_param(struct ib_cm_req_param *param)
+static int cm_validate_req_param(struct ib_cm_req_param *param)
{
/* peer-to-peer not supported */
if (param->peer_to_peer)
(be32_to_cpu(local_qpn) > be32_to_cpu(remote_qpn))));
}
-static inline void cm_format_paths_from_req(struct cm_req_msg *req_msg,
+static void cm_format_paths_from_req(struct cm_req_msg *req_msg,
struct ib_sa_path_rec *primary_path,
struct ib_sa_path_rec *alt_path)
{
return -EINVAL;
}
+ cm_format_rep_event(work);
+
+ spin_lock_irqsave(&cm_id_priv->lock, flags);
+ switch (cm_id_priv->id.state) {
+ case IB_CM_REQ_SENT:
+ case IB_CM_MRA_REQ_RCVD:
+ break;
+ default:
+ spin_unlock_irqrestore(&cm_id_priv->lock, flags);
+ ret = -EINVAL;
+ goto error;
+ }
+
cm_id_priv->timewait_info->work.remote_id = rep_msg->local_comm_id;
cm_id_priv->timewait_info->remote_ca_guid = rep_msg->local_ca_guid;
cm_id_priv->timewait_info->remote_qpn = cm_rep_get_local_qpn(rep_msg);
- spin_lock_irqsave(&cm.lock, flags);
+ spin_lock(&cm.lock);
/* Check for duplicate REP. */
if (cm_insert_remote_id(cm_id_priv->timewait_info)) {
- spin_unlock_irqrestore(&cm.lock, flags);
+ spin_unlock(&cm.lock);
+ spin_unlock_irqrestore(&cm_id_priv->lock, flags);
ret = -EINVAL;
goto error;
}
/* Check for a stale connection. */
if (cm_insert_remote_qpn(cm_id_priv->timewait_info)) {
- spin_unlock_irqrestore(&cm.lock, flags);
+ rb_erase(&cm_id_priv->timewait_info->remote_id_node,
+ &cm.remote_id_table);
+ cm_id_priv->timewait_info->inserted_remote_id = 0;
+ spin_unlock(&cm.lock);
+ spin_unlock_irqrestore(&cm_id_priv->lock, flags);
cm_issue_rej(work->port, work->mad_recv_wc,
IB_CM_REJ_STALE_CONN, CM_MSG_RESPONSE_REP,
NULL, 0);
ret = -EINVAL;
goto error;
}
- spin_unlock_irqrestore(&cm.lock, flags);
-
- cm_format_rep_event(work);
+ spin_unlock(&cm.lock);
- spin_lock_irqsave(&cm_id_priv->lock, flags);
- switch (cm_id_priv->id.state) {
- case IB_CM_REQ_SENT:
- case IB_CM_MRA_REQ_RCVD:
- break;
- default:
- spin_unlock_irqrestore(&cm_id_priv->lock, flags);
- ret = -EINVAL;
- goto error;
- }
cm_id_priv->id.state = IB_CM_REP_RCVD;
cm_id_priv->id.remote_id = rep_msg->local_comm_id;
cm_id_priv->remote_qpn = cm_rep_get_local_qpn(rep_msg);
cm_deref_id(cm_id_priv);
return 0;
-error: cm_cleanup_timewait(cm_id_priv->timewait_info);
+error:
cm_deref_id(cm_id_priv);
return ret;
}
}
EXPORT_SYMBOL(ib_cm_init_qp_attr);
-static __be64 cm_get_ca_guid(struct ib_device *device)
-{
- struct ib_device_attr *device_attr;
- __be64 guid;
- int ret;
-
- device_attr = kmalloc(sizeof *device_attr, GFP_KERNEL);
- if (!device_attr)
- return 0;
-
- ret = ib_query_device(device, device_attr);
- guid = ret ? 0 : device_attr->node_guid;
- kfree(device_attr);
- return guid;
-}
-
static void cm_add_one(struct ib_device *device)
{
struct cm_device *cm_dev;
return;
cm_dev->device = device;
- cm_dev->ca_guid = cm_get_ca_guid(device);
- if (!cm_dev->ca_guid)
- goto error1;
+ cm_dev->ca_guid = device->node_guid;
set_bit(IB_MGMT_METHOD_SEND, reg_req.method_mask);
for (i = 1; i <= device->phys_port_cnt; i++) {
cm_recv_handler,
port);
if (IS_ERR(port->mad_agent))
- goto error2;
+ goto error1;
ret = ib_modify_port(device, i, 0, &port_modify);
if (ret)
- goto error3;
+ goto error2;
}
ib_set_client_data(device, &cm_client, cm_dev);
write_unlock_irqrestore(&cm.device_lock, flags);
return;
-error3:
- ib_unregister_mad_agent(port->mad_agent);
error2:
+ ib_unregister_mad_agent(port->mad_agent);
+error1:
port_modify.set_port_cap_mask = 0;
port_modify.clr_port_cap_mask = IB_PORT_CM_SUP;
while (--i) {
ib_modify_port(device, port->port_num, 0, &port_modify);
ib_unregister_mad_agent(port->mad_agent);
}
-error1:
kfree(cm_dev);
}