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;
 }
 
 /*
_______________________________________________
openib-general mailing list
[EMAIL PROTECTED]
http://openib.org/mailman/listinfo/openib-general

To unsubscribe, please visit http://openib.org/mailman/listinfo/openib-general

Reply via email to