[ofa-general] [PATCH v2] IB/ipoib: use vmap with allocation of tx ring

Eli Cohen eli at dev.mellanox.co.il
Thu Feb 14 06:13:23 PST 2008


 From 2f1870f76ddbfc948aea4847c25d05ae70dd43cf Mon Sep 17 00:00:00 2001
From: Eli Cohen <eli at mellanox.co.il>
Date: Thu, 14 Feb 2008 15:46:33 +0200
Subject: [PATCH] IB/ipoib: use vmap with allocation of tx ring

With the introduction of s/g support in IPOIB, the size of struct ipoib_tx_buf
has increased since it reserves room for the fragments. This caused allocations
to fail when large send queues are required. This patch uses an array of pages
and maps them with vmap to increase the certainty of the allocation to succeed.

Signed-off-by: Eli Cohen <eli at mellanox.co.il>
---
  drivers/infiniband/ulp/ipoib/ipoib.h      |    9 +++++
  drivers/infiniband/ulp/ipoib/ipoib_main.c |   54 ++++++++++++++++++++++++++---
  2 files changed, 58 insertions(+), 5 deletions(-)

diff --git a/drivers/infiniband/ulp/ipoib/ipoib.h b/drivers/infiniband/ulp/ipoib/ipoib.h
index f9b7caa..78a99d6 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib.h
+++ b/drivers/infiniband/ulp/ipoib/ipoib.h
@@ -186,6 +186,12 @@ enum ipoib_cm_state {
  	IPOIB_CM_RX_FLUSH  /* Last WQE Reached event observed */
  };

+struct ipoib_vmap {
+       void           *ptr;
+       struct page   **page_arr;
+       int             npages;
+};
+
  struct ipoib_cm_rx {
  	struct ib_cm_id	       *id;
  	struct ib_qp	       *qp;
@@ -293,6 +299,7 @@ struct ipoib_dev_priv {
  	struct ipoib_rx_buf *rx_ring;

  	spinlock_t	     tx_lock;
+	struct ipoib_vmap    tx_vmap_ring;
  	struct ipoib_tx_buf *tx_ring;
  	unsigned	     tx_head;
  	unsigned	     tx_tail;
@@ -458,6 +465,8 @@ int ipoib_vlan_delete(struct net_device *pdev, unsigned short pkey);
  void ipoib_pkey_poll(struct work_struct *work);
  int ipoib_pkey_dev_delay_open(struct net_device *dev);
  void ipoib_drain_cq(struct net_device *dev);
+int ipoib_vmalloc(struct ipoib_vmap *buf, int size);
+void ipoib_vfree(struct ipoib_vmap *buf);

  #ifdef CONFIG_INFINIBAND_IPOIB_CM

diff --git a/drivers/infiniband/ulp/ipoib/ipoib_main.c b/drivers/infiniband/ulp/ipoib/ipoib_main.c
index f96477a..3a44a42 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib_main.c
+++ b/drivers/infiniband/ulp/ipoib/ipoib_main.c
@@ -92,6 +92,50 @@ static struct ib_client ipoib_client = {
  	.remove = ipoib_remove_one
  };

+int ipoib_vmalloc(struct ipoib_vmap *buf, int size)
+{
+	int     i;
+	int     npages = ALIGN(size, PAGE_SIZE) / PAGE_SIZE;
+	int     ret = -ENOMEM;
+
+	buf->page_arr = kmalloc(npages * sizeof buf->page_arr[0], GFP_KERNEL);
+	if (!buf->page_arr)
+		goto out;
+
+	for (i = 0; i < npages; ++i) {
+		buf->page_arr[i] = alloc_page(GFP_KERNEL);
+		if (!buf->page_arr[i])
+			goto page_fail;
+	}
+
+	buf->npages = npages;
+	buf->ptr = vmap(buf->page_arr, buf->npages, VM_MAP, PAGE_KERNEL);
+	if (!buf->ptr)
+		goto page_fail;
+
+	memset(buf->ptr, 0, size);
+	return 0;
+	
+page_fail:
+	for (; i > 0; --i)
+		__free_page(buf->page_arr[i - 1]);
+
+	kfree(buf->page_arr);
+out:
+	return ret;
+}
+
+void ipoib_vfree(struct ipoib_vmap *buf)
+{
+	int     i;
+
+	vunmap(buf->ptr);
+	for (i = 0; i < buf->npages; ++i)
+		__free_page(buf->page_arr[i]);
+
+	kfree(buf->page_arr);
+}
+
  int ipoib_open(struct net_device *dev)
  {
  	struct ipoib_dev_priv *priv = netdev_priv(dev);
@@ -887,13 +931,13 @@ int ipoib_dev_init(struct net_device *dev, struct ib_device *ca, int port)
  		goto out;
  	}

-	priv->tx_ring = kzalloc(ipoib_sendq_size * sizeof *priv->tx_ring,
-				GFP_KERNEL);
-	if (!priv->tx_ring) {
+	if (ipoib_vmalloc(&priv->tx_vmap_ring, ipoib_sendq_size *
+			  sizeof *priv->tx_ring)) {
  		printk(KERN_WARNING "%s: failed to allocate TX ring (%d entries)\n",
  		       ca->name, ipoib_sendq_size);
  		goto out_rx_ring_cleanup;
  	}
+	priv->tx_ring = priv->tx_vmap_ring.ptr;

  	/* priv->tx_head, tx_tail & tx_outstanding are already 0 */

@@ -903,7 +947,7 @@ int ipoib_dev_init(struct net_device *dev, struct ib_device *ca, int port)
  	return 0;

  out_tx_ring_cleanup:
-	kfree(priv->tx_ring);
+	ipoib_vfree(&priv->tx_vmap_ring);

  out_rx_ring_cleanup:
  	kfree(priv->rx_ring);
@@ -928,7 +972,7 @@ void ipoib_dev_cleanup(struct net_device *dev)
  	ipoib_ib_dev_cleanup(dev);

  	kfree(priv->rx_ring);
-	kfree(priv->tx_ring);
+	ipoib_vfree(&priv->tx_vmap_ring);

  	priv->rx_ring = NULL;
  	priv->tx_ring = NULL;
-- 
1.5.3.8




More information about the general mailing list