[openib-general] [PATCH] mad/agent: Modify receive buffer allocation strategy

Hal Rosenstock halr at voltaire.com
Tue Nov 9 08:49:21 PST 2004


mad/agent: Modify receive buffer allocation strategy
(Inefficiency pointed out by Sean; algorithm described by Roland)

Problem: Currently, if the underlying driver provides a process_mad
routine, a response MAD is allocated every time a MAD is received on
QP 0 or 1.

Solution: The MAD layer can allocate a response MAD when a MAD is
received, and if the process_mad call doesn't actually generate a
response the MAD layer just stashes the response MAD away to use for
the next receive. This should keep the number of allocations within 1
of the number of responses actually generated, but save us from
tracking allocations between two layers.

Index: agent.h
===================================================================
--- agent.h	(revision 1180)
+++ agent.h	(working copy)
@@ -31,7 +31,7 @@
 
 extern int ib_agent_port_close(struct ib_device *device, int port_num);
 
-extern int agent_send(struct ib_mad *mad,
+extern int agent_send(struct ib_mad_private *mad,
 		      struct ib_grh *grh,
 		      struct ib_wc *wc,
 		      struct ib_device *device,
Index: agent_priv.h
===================================================================
--- agent_priv.h	(revision 1180)
+++ agent_priv.h	(working copy)
@@ -33,7 +33,7 @@
 struct ib_agent_send_wr {
 	struct list_head send_list;
 	struct ib_ah *ah;
-	struct ib_mad *mad;
+	struct ib_mad_private *mad;
 	DECLARE_PCI_UNMAP_ADDR(mapping)
 };
 
Index: agent.c
===================================================================
--- agent.c	(revision 1182)
+++ agent.c	(working copy)
@@ -33,7 +33,9 @@
 static spinlock_t ib_agent_port_list_lock = SPIN_LOCK_UNLOCKED;
 static LIST_HEAD(ib_agent_port_list);
 
+extern kmem_cache_t *ib_mad_cache;
 
+
 static inline struct ib_agent_port_private *
 __ib_get_agent_port(struct ib_device *device, int port_num,
 		    struct ib_mad_agent *mad_agent)
@@ -95,7 +97,7 @@
 
 static int agent_mad_send(struct ib_mad_agent *mad_agent,
 			  struct ib_agent_port_private *port_priv,
-			  struct ib_mad *mad,
+			  struct ib_mad_private *mad,
 			  struct ib_grh *grh,
 			  struct ib_wc *wc)
 {
@@ -114,10 +116,10 @@
 
 	/* PCI mapping */
 	gather_list.addr = pci_map_single(mad_agent->device->dma_device,
-					  mad,
-					  sizeof(struct ib_mad),
+					  &mad->grh,
+					  sizeof *mad - sizeof mad->header,
 					  PCI_DMA_TODEVICE);
-	gather_list.length = sizeof(struct ib_mad);
+	gather_list.length = sizeof *mad - sizeof mad->header;
 	gather_list.lkey = (*port_priv->mr).lkey;
 
 	send_wr.next = NULL;
@@ -133,7 +135,7 @@
 	ah_attr.src_path_bits = wc->dlid_path_bits;
 	ah_attr.sl = wc->sl;
 	ah_attr.static_rate = 0;
-	if (mad->mad_hdr.mgmt_class == IB_MGMT_CLASS_PERF_MGMT) {
+	if (mad->mad.mad.mad_hdr.mgmt_class == IB_MGMT_CLASS_PERF_MGMT) {
 		if (wc->wc_flags & IB_WC_GRH) {
 			ah_attr.ah_flags = IB_AH_GRH;
 			/* Should sgid be looked up ? */
@@ -162,14 +164,14 @@
 	}
 
 	send_wr.wr.ud.ah = agent_send_wr->ah;
-	if (mad->mad_hdr.mgmt_class == IB_MGMT_CLASS_PERF_MGMT) {
+	if (mad->mad.mad.mad_hdr.mgmt_class == IB_MGMT_CLASS_PERF_MGMT) {
 		send_wr.wr.ud.pkey_index = wc->pkey_index;
 		send_wr.wr.ud.remote_qkey = IB_QP1_QKEY;
 	} else {
 		send_wr.wr.ud.pkey_index = 0; /* Should only matter for GMPs */
 		send_wr.wr.ud.remote_qkey = 0; /* for SMPs */
 	}
-	send_wr.wr.ud.mad_hdr = (struct ib_mad_hdr *)mad;
+	send_wr.wr.ud.mad_hdr = &mad->mad.mad.mad_hdr;
 	send_wr.wr_id = ++port_priv->wr_id;
 
 	pci_unmap_addr_set(agent_send_wr, mapping, gather_list.addr);
@@ -180,7 +182,8 @@
 		spin_unlock_irqrestore(&port_priv->send_list_lock, flags);
 		pci_unmap_single(mad_agent->device->dma_device,
 				 pci_unmap_addr(agent_send_wr, mapping),
-				 sizeof(struct ib_mad),
+				 sizeof(struct ib_mad_private) -
+				 sizeof(struct ib_mad_private_header),
 				 PCI_DMA_TODEVICE);
 		ib_destroy_ah(agent_send_wr->ah);
 		kfree(agent_send_wr);
@@ -195,7 +198,7 @@
 	return ret;
 }
 
-int agent_send(struct ib_mad *mad,
+int agent_send(struct ib_mad_private *mad,
 	       struct ib_grh *grh,
 	       struct ib_wc *wc,
 	       struct ib_device *device,
@@ -212,7 +215,7 @@
 	}
 
 	/* Get mad agent based on mgmt_class in MAD */
-	switch (mad->mad_hdr.mgmt_class) {
+	switch (mad->mad.mad.mad_hdr.mgmt_class) {
 		case IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE:
 			mad_agent = port_priv->dr_smp_agent;
 			break;
@@ -269,13 +272,14 @@
 	/* Unmap PCI */
 	pci_unmap_single(mad_agent->device->dma_device,
 			 pci_unmap_addr(agent_send_wr, mapping),
-			 sizeof(struct ib_mad),
+			 sizeof(struct ib_mad_private) -
+			 sizeof(struct ib_mad_private_header),
 			 PCI_DMA_TODEVICE);
 
 	ib_destroy_ah(agent_send_wr->ah);
 
 	/* Release allocated memory */
-	kfree(agent_send_wr->mad);
+	kmem_cache_free(ib_mad_cache, agent_send_wr->mad);
 	kfree(agent_send_wr);
 }
 
Index: mad.c
===================================================================
--- mad.c	(revision 1181)
+++ mad.c	(working copy)
@@ -69,7 +69,7 @@
 MODULE_AUTHOR("Sean Hefty");
 
 
-static kmem_cache_t *ib_mad_cache;
+kmem_cache_t *ib_mad_cache;
 static struct list_head ib_mad_port_list;
 static u32 ib_mad_client_id = 0;
 
@@ -83,7 +83,8 @@
 static int add_mad_reg_req(struct ib_mad_reg_req *mad_reg_req,
 			   struct ib_mad_agent_private *priv);
 static void remove_mad_reg_req(struct ib_mad_agent_private *priv); 
-static int ib_mad_post_receive_mad(struct ib_mad_qp_info *qp_info);
+static int ib_mad_post_receive_mad(struct ib_mad_qp_info *qp_info,
+				   struct ib_mad_private *mad);
 static int ib_mad_post_receive_mads(struct ib_mad_qp_info *qp_info);
 static void cancel_mads(struct ib_mad_agent_private *mad_agent_priv);
 static void ib_mad_complete_send_wr(struct ib_mad_send_wr_private *mad_send_wr,
@@ -1067,12 +1068,17 @@
 {
 	struct ib_mad_qp_info *qp_info;
 	struct ib_mad_private_header *mad_priv_hdr;
-	struct ib_mad_private *recv;
+	struct ib_mad_private *recv, *response;
 	struct ib_mad_list_head *mad_list;
 	struct ib_mad_agent_private *mad_agent;
 	struct ib_smp *smp;
 	int solicited;
 
+	response = kmem_cache_alloc(ib_mad_cache, GFP_KERNEL);
+	if (!response)
+		printk(KERN_ERR PFX "ib_mad_recv_done_handler no memory "
+		       "for response buffer\n");
+
 	mad_list = (struct ib_mad_list_head *)(unsigned long)wc->wr_id;
 	qp_info = mad_list->mad_queue->qp_info;
 	dequeue_mad(mad_list);
@@ -1119,11 +1125,9 @@
 
 	/* Give driver "right of first refusal" on incoming MAD */
 	if (port_priv->device->process_mad) {
-		struct ib_mad *response;
 		struct ib_grh *grh;
 		int ret;
 
-		response = kmalloc(sizeof(struct ib_mad), GFP_KERNEL);
 		if (!response) {
 			printk(KERN_ERR PFX "No memory for response MAD\n");
 			/*
@@ -1137,32 +1141,29 @@
 						     port_priv->port_num,
 						     wc->slid,
 						     recv->header.recv_buf.mad,
-						     response);
+						     &response->mad.mad);
 		if (ret & IB_MAD_RESULT_SUCCESS) {
 			if (ret & IB_MAD_RESULT_REPLY) {
-				if (response->mad_hdr.mgmt_class ==
+				if (response->mad.mad.mad_hdr.mgmt_class ==
 				    IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE) {
 					if (!smi_handle_dr_smp_recv(
-					    (struct ib_smp *)response,
+					    (struct ib_smp *)&response->mad.mad,
 					    port_priv->device->node_type,
 					    port_priv->port_num,
 					    port_priv->device->phys_port_cnt)) {
-						kfree(response);
 						goto out;
 					}
 				}
 				/* Send response */
 				grh = (void *)recv->header.recv_buf.mad -
 				      sizeof(struct ib_grh);
-				if (agent_send(response, grh, wc,
-					       port_priv->device,
-					       port_priv->port_num)) {
-					kfree(response);
-				}
+				if (!agent_send(response, grh, wc,
+						port_priv->device,
+						port_priv->port_num))
+					response = NULL;
 				goto out;
 			}
-		} else
-			kfree(response);
+		} 
 	}
 
 	/* Determine corresponding MAD agent for incoming receive MAD */
@@ -1183,7 +1184,7 @@
 		kmem_cache_free(ib_mad_cache, recv);
 
 	/* Post another receive request for this QP */
-	ib_mad_post_receive_mad(qp_info);
+	ib_mad_post_receive_mad(qp_info, response);
 }
 
 static void adjust_timeout(struct ib_mad_agent_private *mad_agent_priv)
@@ -1491,7 +1492,8 @@
 	queue_work(port_priv->wq, &port_priv->work);
 }
 
-static int ib_mad_post_receive_mad(struct ib_mad_qp_info *qp_info)
+static int ib_mad_post_receive_mad(struct ib_mad_qp_info *qp_info,
+				   struct ib_mad_private *mad)
 {
 	struct ib_mad_private *mad_priv;
 	struct ib_sge sg_list;
@@ -1499,19 +1501,23 @@
 	struct ib_recv_wr *bad_recv_wr;
 	int ret;
 
-	/* 
-	 * Allocate memory for receive buffer.
-	 * This is for both MAD and private header
-	 * which contains the receive tracking structure.
-	 * By prepending this header, there is one rather 
-	 * than two memory allocations.
-	 */
-	mad_priv = kmem_cache_alloc(ib_mad_cache,
-				    (in_atomic() || irqs_disabled()) ?
-				    GFP_ATOMIC : GFP_KERNEL);
-	if (!mad_priv) {
-		printk(KERN_ERR PFX "No memory for receive buffer\n");
-		return -ENOMEM;
+	if (mad)
+		mad_priv = mad;
+	else {
+		/* 
+		 * Allocate memory for receive buffer.
+		 * This is for both MAD and private header
+		 * which contains the receive tracking structure.
+		 * By prepending this header, there is one rather 
+		 * than two memory allocations.
+		 */
+		mad_priv = kmem_cache_alloc(ib_mad_cache,
+					    (in_atomic() || irqs_disabled()) ?
+					    GFP_ATOMIC : GFP_KERNEL);
+		if (!mad_priv) {
+			printk(KERN_ERR PFX "No memory for receive buffer\n");
+			return -ENOMEM;
+		}
 	}
 
 	/* Setup scatter list */
@@ -1559,7 +1565,7 @@
 	int i, ret;
 
 	for (i = 0; i < IB_MAD_QP_RECV_SIZE; i++) {
-		ret = ib_mad_post_receive_mad(qp_info);
+		ret = ib_mad_post_receive_mad(qp_info, NULL);
 		if (ret) {
 			printk(KERN_ERR PFX "receive post %d failed "
 				"on %s port %d\n", i + 1,






More information about the general mailing list