[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