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