[openib-general] [PATCH] Add send queuing to MAD agent
Sean Hefty
mshefty at ichips.intel.com
Mon Sep 27 12:56:13 PDT 2004
This patch adds send queuing at the MAD agent level. The queuing will eventually be needed for request/response/timeout/RMPP/QP overflow/send optimization/unregistration purposes. The patch restructures part of the layering of the send side code for RMPP/QP overflow purposes, and fixes a bug where MADs could be posted on the QP outside of a lock, resulting in out of order completions.
- Sean
--
Index: access/ib_mad_priv.h
===================================================================
--- access/ib_mad_priv.h (revision 893)
+++ access/ib_mad_priv.h (working copy)
@@ -105,6 +105,10 @@
struct ib_mad_agent agent;
struct ib_mad_reg_req *reg_req;
struct ib_mad_port_private *port_priv;
+
+ spinlock_t send_list_lock;
+ struct list_head send_list;
+
atomic_t refcount;
wait_queue_head_t wait;
u8 rmpp_version;
@@ -112,9 +116,11 @@
struct ib_mad_send_wr_private {
struct list_head send_list;
+ struct list_head agent_send_list;
struct ib_mad_agent *agent;
u64 wr_id; /* client WRID */
int timeout_ms;
+ int is_active;
};
struct ib_mad_mgmt_method_table {
Index: access/ib_mad.c
===================================================================
--- access/ib_mad.c (revision 893)
+++ access/ib_mad.c (working copy)
@@ -223,6 +223,8 @@
list_add_tail(&mad_agent_priv->agent_list, &port_priv->agent_list);
spin_unlock_irqrestore(&port_priv->reg_lock, flags);
+ spin_lock_init(&mad_agent_priv->send_list_lock);
+ INIT_LIST_HEAD(&mad_agent_priv->send_list);
atomic_set(&mad_agent_priv->refcount, 1);
init_waitqueue_head(&mad_agent_priv->wait);
mad_agent_priv->port_priv = port_priv;
@@ -269,6 +271,35 @@
}
EXPORT_SYMBOL(ib_unregister_mad_agent);
+static int ib_send_mad(struct ib_mad_agent_private *mad_agent_priv,
+ struct ib_mad_send_wr_private *mad_send_wr,
+ struct ib_send_wr *send_wr,
+ struct ib_send_wr **bad_send_wr)
+{
+ struct ib_mad_port_private *port_priv;
+ unsigned long flags;
+ int ret;
+
+ port_priv = mad_agent_priv->port_priv;
+
+ /* Replace user's WR ID with our own to find WR on completion. */
+ mad_send_wr->wr_id = send_wr->wr_id;
+ send_wr->wr_id = (unsigned long)mad_send_wr;
+
+ spin_lock_irqsave(&port_priv->send_list_lock, flags);
+ ret = ib_post_send(mad_agent_priv->agent.qp, send_wr, bad_send_wr);
+ if (!ret) {
+ list_add_tail(&mad_send_wr->send_list,
+ &port_priv->send_posted_mad_list);
+ port_priv->send_posted_mad_count++;
+ } else {
+ printk(KERN_NOTICE "ib_post_send failed\n");
+ *bad_send_wr = send_wr;
+ }
+ spin_unlock_irqrestore(&port_priv->send_list_lock, flags);
+ return ret;
+}
+
/*
* ib_post_send_mad - Posts MAD(s) to the send queue of the QP associated
* with the registered client
@@ -312,44 +343,35 @@
return -ENOMEM;
}
- /* Initialize MAD send WR tracking structure */
+ /* Track sent MAD with agent. */
+ spin_lock_irqsave(&mad_agent_priv->send_list_lock, flags);
+ list_add_tail(&mad_send_wr->agent_send_list,
+ &mad_agent_priv->send_list);
+ spin_unlock_irqrestore(&mad_agent_priv->send_list_lock, flags);
+
+ /* Reference MAD agent until send completes. */
+ atomic_inc(&mad_agent_priv->refcount);
mad_send_wr->agent = mad_agent;
- mad_send_wr->wr_id = cur_send_wr->wr_id;
- /* Timeout valid only when MAD is a request !!! */
mad_send_wr->timeout_ms = cur_send_wr->wr.ud.timeout_ms;
+ mad_send_wr->is_active = 1;
+ wr = *cur_send_wr;
wr.next = NULL;
- wr.opcode = IB_WR_SEND; /* cur_send_wr->opcode ? */
- wr.wr_id = (unsigned long)mad_send_wr;
- wr.sg_list = cur_send_wr->sg_list;
- wr.num_sge = cur_send_wr->num_sge;
- wr.wr.ud.remote_qpn = cur_send_wr->wr.ud.remote_qpn;
- wr.wr.ud.remote_qkey = cur_send_wr->wr.ud.remote_qkey;
- wr.wr.ud.pkey_index = cur_send_wr->wr.ud.pkey_index;
- wr.wr.ud.ah = cur_send_wr->wr.ud.ah;
- wr.send_flags = IB_SEND_SIGNALED; /* cur_send_wr->send_flags ? */
- /* Link send WR into posted send MAD list */
- spin_lock_irqsave(&port_priv->send_list_lock, flags);
- list_add_tail(&mad_send_wr->send_list,
- &port_priv->send_posted_mad_list);
- port_priv->send_posted_mad_count++;
- spin_unlock_irqrestore(&port_priv->send_list_lock, flags);
-
- /* Reference MAD agent until send completes. */
- atomic_inc(&mad_agent_priv->refcount);
-
- ret = ib_post_send(mad_agent->qp, &wr, &bad_wr);
+ ret = ib_send_mad(mad_agent_priv, mad_send_wr, &wr, &bad_wr);
if (ret) {
- /* Unlink from posted send MAD list */
- spin_unlock_irqrestore(&port_priv->send_list_lock, flags);
- list_del(&mad_send_wr->send_list);
- port_priv->send_posted_mad_count--;
- spin_unlock_irqrestore(&port_priv->send_list_lock, flags);
+ /* Handle QP overrun separately... -ENOMEM */
+
+ /* Fail send request */
+ spin_lock_irqsave(&mad_agent_priv->send_list_lock,
+ flags);
+ list_del(&mad_send_wr->agent_send_list);
+ spin_unlock_irqrestore(&mad_agent_priv->send_list_lock,
+ flags);
*bad_send_wr = cur_send_wr;
if (atomic_dec_and_test(&mad_agent_priv->refcount))
wake_up(&mad_agent_priv->wait);
- printk(KERN_NOTICE "ib_post_mad_send failed\n");
+ printk(KERN_NOTICE "ib_send_mad failed\n");
return ret;
}
cur_send_wr= next_send_wr;
@@ -786,57 +808,74 @@
return;
}
+/*
+ * Process a send work completion.
+ */
+static void ib_mad_complete_send_wr(struct ib_mad_send_wr_private *mad_send_wr,
+ struct ib_mad_send_wc *mad_send_wc)
+{
+ struct ib_mad_agent_private *mad_agent_priv;
+ unsigned long flags;
+
+ mad_agent_priv = container_of(mad_send_wr->agent,
+ struct ib_mad_agent_private, agent);
+
+ /* Check whether timeout was requested !!! */
+ mad_send_wr->is_active = 0;
+
+ /* Handle RMPP... */
+
+ /* Remove send from MAD agent and notify client of completion. */
+ spin_lock_irqsave(&mad_agent_priv->send_list_lock,
+ flags);
+ list_del(&mad_send_wr->agent_send_list);
+ spin_unlock_irqrestore(&mad_agent_priv->send_list_lock,
+ flags);
+ mad_agent_priv->agent.send_handler(&mad_agent_priv->agent, mad_send_wc);
+
+ /* Release reference taken when sending. */
+ if (atomic_dec_and_test(&mad_agent_priv->refcount))
+ wake_up(&mad_agent_priv->wait);
+
+ kfree(mad_send_wr);
+}
+
static void ib_mad_send_done_handler(struct ib_mad_port_private *port_priv,
struct ib_wc *wc)
{
- struct ib_mad_send_wr_private *send_wr;
- struct ib_mad_agent_private *mad_agent_priv;
- unsigned long flags;
+ struct ib_mad_send_wr_private *mad_send_wr;
+ unsigned long flags;
/* Completion corresponds to first entry on posted MAD send list */
spin_lock_irqsave(&port_priv->send_list_lock, flags);
- if (!list_empty(&port_priv->send_posted_mad_list)) {
- send_wr = list_entry(&port_priv->send_posted_mad_list,
- struct ib_mad_send_wr_private,
- send_list);
-
- if (send_wr->wr_id != wc->wr_id) {
- printk(KERN_ERR "Send completion WR ID 0x%Lx doesn't match posted send WR ID 0x%Lx\n", wc->wr_id, send_wr->wr_id);
-
- goto error;
- }
-
- mad_agent_priv = container_of(send_wr->agent,
- struct ib_mad_agent_private, agent);
- /* Check whether timeout was requested !!! */
-
- /* Remove from posted send MAD list */
- list_del(&send_wr->send_list);
- port_priv->send_posted_mad_count--;
+ if (list_empty(&port_priv->send_posted_mad_list)) {
+ printk(KERN_ERR "Send completion WR ID 0x%Lx but send list "
+ "is empty\n", wc->wr_id);
+ goto error;
+ }
- } else {
- printk(KERN_ERR "Send completion WR ID 0x%Lx but send list is empty\n", wc->wr_id);
+ mad_send_wr = list_entry(&port_priv->send_posted_mad_list,
+ struct ib_mad_send_wr_private,
+ send_list);
+ if (mad_send_wr->wr_id != wc->wr_id) {
+ printk(KERN_ERR "Send completion WR ID 0x%Lx doesn't match "
+ "posted send WR ID 0x%Lx\n", wc->wr_id, mad_send_wr->wr_id);
goto error;
}
+
+ /* Remove from posted send MAD list */
+ list_del(&mad_send_wr->send_list);
+ port_priv->send_posted_mad_count--;
spin_unlock_irqrestore(&port_priv->send_list_lock, flags);
/* Restore client wr_id in WC */
- wc->wr_id = send_wr->wr_id;
-
- /* Invoke client send callback */
- send_wr->agent->send_handler(send_wr->agent,
- (struct ib_mad_send_wc *)wc);
+ wc->wr_id = mad_send_wr->wr_id;
- /* Release reference taken when sending. */
- if (atomic_dec_and_test(&mad_agent_priv->refcount))
- wake_up(&mad_agent_priv->wait);
-
- kfree(send_wr);
+ ib_mad_complete_send_wr(mad_send_wr, (struct ib_mad_send_wc*)wc);
return;
error:
spin_unlock_irqrestore(&port_priv->send_list_lock, flags);
- return;
}
/*
More information about the general
mailing list