[ofa-general] [PATCH] ipoib - scatter/gather suopport

Eli Cohen eli at mellanox.co.il
Sun Aug 12 04:43:33 PDT 2007


Add scatter/gather support to ipoib

Signed-off-by: Eli Cohen <eli at mellnaox.co.il>

---

Index: linux-2.6.23-rc1/drivers/infiniband/ulp/ipoib/ipoib_main.c
===================================================================
--- linux-2.6.23-rc1.orig/drivers/infiniband/ulp/ipoib/ipoib_main.c	2007-08-02 14:08:29.000000000 +0300
+++ linux-2.6.23-rc1/drivers/infiniband/ulp/ipoib/ipoib_main.c	2007-08-02 14:31:02.000000000 +0300
@@ -1083,7 +1083,7 @@ static struct net_device *ipoib_add_port
 
 	pdev = to_pci_dev(hca->dma_device);
 	if (pdev->dma_mask & DMA_64BIT_MASK)
-		priv->dev->features |= NETIF_F_HIGHDMA;
+		priv->dev->features |= NETIF_F_HIGHDMA | NETIF_F_SG;
 
 	result = ib_query_pkey(hca, port, 0, &priv->pkey);
 	if (result) {
Index: linux-2.6.23-rc1/drivers/infiniband/ulp/ipoib/ipoib.h
===================================================================
--- linux-2.6.23-rc1.orig/drivers/infiniband/ulp/ipoib/ipoib.h	2007-07-10 21:56:30.000000000 +0300
+++ linux-2.6.23-rc1/drivers/infiniband/ulp/ipoib/ipoib.h	2007-08-02 14:31:02.000000000 +0300
@@ -120,9 +120,14 @@ struct ipoib_rx_buf {
 	u64		mapping;
 };
 
+struct ipoib_mapping_st {
+	u64	addr;
+	u16	size;
+};
+
 struct ipoib_tx_buf {
 	struct sk_buff *skb;
-	u64		mapping;
+	struct ipoib_mapping_st  mapping[MAX_SKB_FRAGS + 1];
 };
 
 struct ib_cm_id;
@@ -269,7 +274,7 @@ struct ipoib_dev_priv {
 	struct ipoib_tx_buf *tx_ring;
 	unsigned             tx_head;
 	unsigned             tx_tail;
-	struct ib_sge        tx_sge;
+	struct ib_sge        tx_sge[MAX_SKB_FRAGS + 1];
 	struct ib_send_wr    tx_wr;
 
 	struct ib_wc ibwc[IPOIB_NUM_WC];
Index: linux-2.6.23-rc1/drivers/infiniband/ulp/ipoib/ipoib_ib.c
===================================================================
--- linux-2.6.23-rc1.orig/drivers/infiniband/ulp/ipoib/ipoib_ib.c	2007-08-02 11:44:43.000000000 +0300
+++ linux-2.6.23-rc1/drivers/infiniband/ulp/ipoib/ipoib_ib.c	2007-08-02 14:31:02.000000000 +0300
@@ -239,6 +239,24 @@ repost:
 			   "for buf %d\n", wr_id);
 }
 
+static int dma_unmap_list(struct ib_device *ca, struct ipoib_mapping_st *map,
+			   u16 n)
+{
+	int i, len;
+
+	BUG_ON(!n);
+	ib_dma_unmap_single(ca, map[0].addr, map[0].size, DMA_TO_DEVICE);
+	len = map[0].size;
+
+	for (i = 1; i < n; ++i) {
+		ib_dma_unmap_page(ca, map[i].addr, map[i].size,
+				  DMA_TO_DEVICE);
+		len += map[i].size;
+	}
+
+	return len;
+}
+
 static void ipoib_ib_handle_tx_wc(struct net_device *dev, struct ib_wc *wc)
 {
 	struct ipoib_dev_priv *priv = netdev_priv(dev);
@@ -256,12 +274,9 @@ static void ipoib_ib_handle_tx_wc(struct
 	}
 
 	tx_req = &priv->tx_ring[wr_id];
-
-	ib_dma_unmap_single(priv->ca, tx_req->mapping,
-			    tx_req->skb->len, DMA_TO_DEVICE);
-
+	priv->stats.tx_bytes += dma_unmap_list(priv->ca, tx_req->mapping,
+					       skb_shinfo(tx_req->skb)->nr_frags + 1);
 	++priv->stats.tx_packets;
-	priv->stats.tx_bytes += tx_req->skb->len;
 
 	dev_kfree_skb_any(tx_req->skb);
 
@@ -343,13 +358,17 @@ void ipoib_ib_completion(struct ib_cq *c
 static inline int post_send(struct ipoib_dev_priv *priv,
 			    unsigned int wr_id,
 			    struct ib_ah *address, u32 qpn,
-			    u64 addr, int len)
+			    struct ipoib_mapping_st *mapping, int ngather)
 {
 	struct ib_send_wr *bad_wr;
+	int i;
 
-	priv->tx_sge.addr             = addr;
-	priv->tx_sge.length           = len;
+	for (i = 0; i < ngather; ++i) {
+		priv->tx_sge[i].addr = mapping[i].addr;
+		priv->tx_sge[i].length = mapping[i].size;
+	}
 
+	priv->tx_wr.num_sge 	      = ngather;
 	priv->tx_wr.wr_id 	      = wr_id;
 	priv->tx_wr.wr.ud.remote_qpn  = qpn;
 	priv->tx_wr.wr.ud.ah 	      = address;
@@ -362,7 +381,9 @@ void ipoib_send(struct net_device *dev, 
 {
 	struct ipoib_dev_priv *priv = netdev_priv(dev);
 	struct ipoib_tx_buf *tx_req;
+	struct skb_frag_struct *frag;
 	u64 addr;
+	unsigned short i;
 
 	if (unlikely(skb->len > priv->mcast_mtu + IPOIB_ENCAP_LEN)) {
 		ipoib_warn(priv, "packet len %d (> %d) too long to send, dropping\n",
@@ -385,21 +406,32 @@ void ipoib_send(struct net_device *dev, 
 	 */
 	tx_req = &priv->tx_ring[priv->tx_head & (ipoib_sendq_size - 1)];
 	tx_req->skb = skb;
-	addr = ib_dma_map_single(priv->ca, skb->data, skb->len,
+
+	addr = ib_dma_map_single(priv->ca, skb->data, skb_headlen(skb),
 				 DMA_TO_DEVICE);
 	if (unlikely(ib_dma_mapping_error(priv->ca, addr))) {
 		++priv->stats.tx_errors;
 		dev_kfree_skb_any(skb);
 		return;
 	}
-	tx_req->mapping = addr;
+        tx_req->mapping[0].addr = addr;
+        tx_req->mapping[0].size = skb_headlen(skb);
+
+	for (i = 0; i < skb_shinfo(skb)->nr_frags; ++i) {
+		frag = &skb_shinfo(skb)->frags[i];
+		addr = ib_dma_map_page(priv->ca, frag->page, frag->page_offset,
+				       frag->size, DMA_TO_DEVICE);
+		if (unlikely(ib_dma_mapping_error(priv->ca, addr)))
+			goto map_err;
+
+		tx_req->mapping[i + 1].addr = addr;
+		tx_req->mapping[i + 1].size = frag->size;
+	}
 
 	if (unlikely(post_send(priv, priv->tx_head & (ipoib_sendq_size - 1),
-			       address->ah, qpn, addr, skb->len))) {
+			       address->ah, qpn, tx_req->mapping, skb_shinfo(skb)->nr_frags + 1))) {
 		ipoib_warn(priv, "post_send failed\n");
-		++priv->stats.tx_errors;
-		ib_dma_unmap_single(priv->ca, addr, skb->len, DMA_TO_DEVICE);
-		dev_kfree_skb_any(skb);
+		goto map_err;
 	} else {
 		dev->trans_start = jiffies;
 
@@ -412,6 +444,11 @@ void ipoib_send(struct net_device *dev, 
 			set_bit(IPOIB_FLAG_NETIF_STOPPED, &priv->flags);
 		}
 	}
+	return;
+
+map_err:
+	dma_unmap_list(priv->ca, tx_req->mapping, i + 1);
+	dev_kfree_skb_any(skb);
 }
 
 static void __ipoib_reap_ah(struct net_device *dev)
@@ -604,10 +641,8 @@ int ipoib_ib_dev_stop(struct net_device 
 			while ((int) priv->tx_tail - (int) priv->tx_head < 0) {
 				tx_req = &priv->tx_ring[priv->tx_tail &
 							(ipoib_sendq_size - 1)];
-				ib_dma_unmap_single(priv->ca,
-						    tx_req->mapping,
-						    tx_req->skb->len,
-						    DMA_TO_DEVICE);
+				dma_unmap_list(priv->ca, tx_req->mapping,
+					       skb_shinfo(tx_req->skb)->nr_frags + 1);
 				dev_kfree_skb_any(tx_req->skb);
 				++priv->tx_tail;
 			}
Index: linux-2.6.23-rc1/drivers/infiniband/ulp/ipoib/ipoib_verbs.c
===================================================================
--- linux-2.6.23-rc1.orig/drivers/infiniband/ulp/ipoib/ipoib_verbs.c	2007-07-10 21:56:30.000000000 +0300
+++ linux-2.6.23-rc1/drivers/infiniband/ulp/ipoib/ipoib_verbs.c	2007-08-02 14:31:02.000000000 +0300
@@ -149,14 +149,14 @@ int ipoib_transport_dev_init(struct net_
 		.cap = {
 			.max_send_wr  = ipoib_sendq_size,
 			.max_recv_wr  = ipoib_recvq_size,
-			.max_send_sge = 1,
+			.max_send_sge = MAX_SKB_FRAGS + 1,
 			.max_recv_sge = 1
 		},
 		.sq_sig_type = IB_SIGNAL_ALL_WR,
 		.qp_type     = IB_QPT_UD
 	};
 
-	int ret, size;
+	int ret, size, i;
 
 	priv->pd = ib_alloc_pd(priv->ca);
 	if (IS_ERR(priv->pd)) {
@@ -197,11 +197,11 @@ int ipoib_transport_dev_init(struct net_
 	priv->dev->dev_addr[2] = (priv->qp->qp_num >>  8) & 0xff;
 	priv->dev->dev_addr[3] = (priv->qp->qp_num      ) & 0xff;
 
-	priv->tx_sge.lkey 	= priv->mr->lkey;
+	for (i = 0; i < MAX_SKB_FRAGS + 1; ++i)
+		priv->tx_sge[i].lkey 	= priv->mr->lkey;
 
 	priv->tx_wr.opcode 	= IB_WR_SEND;
-	priv->tx_wr.sg_list 	= &priv->tx_sge;
-	priv->tx_wr.num_sge 	= 1;
+	priv->tx_wr.sg_list 	= priv->tx_sge;
 	priv->tx_wr.send_flags 	= IB_SEND_SIGNALED;
 
 	return 0;
Index: linux-2.6.23-rc1/drivers/infiniband/ulp/ipoib/ipoib_cm.c
===================================================================
--- linux-2.6.23-rc1.orig/drivers/infiniband/ulp/ipoib/ipoib_cm.c	2007-08-02 11:44:43.000000000 +0300
+++ linux-2.6.23-rc1/drivers/infiniband/ulp/ipoib/ipoib_cm.c	2007-08-02 14:31:02.000000000 +0300
@@ -495,8 +495,8 @@ static inline int post_send(struct ipoib
 {
 	struct ib_send_wr *bad_wr;
 
-	priv->tx_sge.addr             = addr;
-	priv->tx_sge.length           = len;
+	priv->tx_sge[0].addr          = addr;
+	priv->tx_sge[0].length        = len;
 
 	priv->tx_wr.wr_id 	      = wr_id;
 
@@ -537,7 +537,7 @@ void ipoib_cm_send(struct net_device *de
 		return;
 	}
 
-	tx_req->mapping = addr;
+	tx_req->mapping[0].addr = addr;
 
 	if (unlikely(post_send(priv, tx, tx->tx_head & (ipoib_sendq_size - 1),
 			        addr, skb->len))) {
@@ -577,7 +577,7 @@ static void ipoib_cm_handle_tx_wc(struct
 
 	tx_req = &tx->tx_ring[wr_id];
 
-	ib_dma_unmap_single(priv->ca, tx_req->mapping, tx_req->skb->len, DMA_TO_DEVICE);
+	ib_dma_unmap_single(priv->ca, tx_req->mapping[0].addr, tx_req->skb->len, DMA_TO_DEVICE);
 
 	/* FIXME: is this right? Shouldn't we only increment on success? */
 	++priv->stats.tx_packets;
@@ -981,7 +981,7 @@ static void ipoib_cm_tx_destroy(struct i
 	if (p->tx_ring) {
 		while ((int) p->tx_tail - (int) p->tx_head < 0) {
 			tx_req = &p->tx_ring[p->tx_tail & (ipoib_sendq_size - 1)];
-			ib_dma_unmap_single(priv->ca, tx_req->mapping, tx_req->skb->len,
+			ib_dma_unmap_single(priv->ca, tx_req->mapping[0].addr, tx_req->skb->len,
 					 DMA_TO_DEVICE);
 			dev_kfree_skb_any(tx_req->skb);
 			++p->tx_tail;




More information about the general mailing list