>From 82401698d675e97aca4d3430a0f8a0fea893c64f Mon Sep 17 00:00:00 2001
From: Yevgeny Petrilin <[EMAIL PROTECTED]>
Date: Thu, 17 Apr 2008 15:40:59 +0300
Subject: [PATCH] mlx4: Qp range reservation

Prior to allocating a qp, one need to reserve an aligned range of qps.
The change is made to enable allocation of consecutive qps.

Signed-off-by: Yevgeny Petrilin <[EMAIL PROTECTED]>
---
 drivers/infiniband/hw/mlx4/qp.c |    9 ++++
 drivers/net/mlx4/alloc.c        |   99 ++++++++++++++++++++++++++++++++++++--
 drivers/net/mlx4/mlx4.h         |    6 ++
 drivers/net/mlx4/qp.c           |   44 ++++++++++++-----
 include/linux/mlx4/device.h     |    5 ++-
 5 files changed, 143 insertions(+), 20 deletions(-)

diff --git a/drivers/infiniband/hw/mlx4/qp.c b/drivers/infiniband/hw/mlx4/qp.c
index e65b8e4..c21a9a3 100644
--- a/drivers/infiniband/hw/mlx4/qp.c
+++ b/drivers/infiniband/hw/mlx4/qp.c
@@ -545,6 +545,11 @@ static int create_qp_common(struct mlx4_ib_dev *dev, 
struct ib_pd *pd,
                }
        }

+       if (!sqpn)
+               err = mlx4_qp_reserve_range(dev->dev, 1, 1, &sqpn);
+       if (err)
+               goto err_wrid;
+
        err = mlx4_qp_alloc(dev->dev, sqpn, &qp->mqp);
        if (err)
                goto err_wrid;
@@ -655,6 +660,10 @@ static void destroy_qp_common(struct mlx4_ib_dev *dev, 
struct mlx4_ib_qp *qp,
        mlx4_ib_unlock_cqs(send_cq, recv_cq);

        mlx4_qp_free(dev->dev, &qp->mqp);
+
+       if (!is_sqp(dev, qp))
+               mlx4_qp_release_range(dev->dev, qp->mqp.qpn, 1);
+
        mlx4_mtt_cleanup(dev->dev, &qp->mtt);

        if (is_user) {
diff --git a/drivers/net/mlx4/alloc.c b/drivers/net/mlx4/alloc.c
index b6b00eb..52b4af3 100644
--- a/drivers/net/mlx4/alloc.c
+++ b/drivers/net/mlx4/alloc.c
@@ -44,15 +44,18 @@ u32 mlx4_bitmap_alloc(struct mlx4_bitmap *bitmap)

        spin_lock(&bitmap->lock);

-       obj = find_next_zero_bit(bitmap->table, bitmap->max, bitmap->last);
-       if (obj >= bitmap->max) {
+       obj = find_next_zero_bit(bitmap->table, bitmap->effective_max,
+                                bitmap->last);
+       if (obj >= bitmap->effective_max) {
                bitmap->top = (bitmap->top + bitmap->max) & bitmap->mask;
-               obj = find_first_zero_bit(bitmap->table, bitmap->max);
+               obj = find_first_zero_bit(bitmap->table, bitmap->effective_max);
        }

-       if (obj < bitmap->max) {
+       if (obj < bitmap->effective_max) {
                set_bit(obj, bitmap->table);
-               bitmap->last = (obj + 1) & (bitmap->max - 1);
+               bitmap->last = (obj + 1);
+               if (bitmap->last == bitmap->effective_max)
+                       bitmap->last = 0;
                obj |= bitmap->top;
        } else
                obj = -1;
@@ -73,7 +76,83 @@ void mlx4_bitmap_free(struct mlx4_bitmap *bitmap, u32 obj)
        spin_unlock(&bitmap->lock);
 }

-int mlx4_bitmap_init(struct mlx4_bitmap *bitmap, u32 num, u32 mask, u32 
reserved)
+static unsigned long find_aligned_range(unsigned long *bitmap,
+                                       u32 start, u32 nbits,
+                                       int len, int align)
+{
+       unsigned long end, i;
+
+again:
+       start = ALIGN(start, align);
+       while ((start < nbits) && test_bit(start, bitmap))
+               start += align;
+       if (start >= nbits)
+               return -1;
+
+       end = start+len;
+       if (end > nbits)
+               return -1;
+       for (i = start+1; i < end; i++) {
+               if (test_bit(i, bitmap)) {
+                       start = i+1;
+                       goto again;
+               }
+       }
+       return start;
+}
+
+u32 mlx4_bitmap_alloc_range(struct mlx4_bitmap *bitmap, int cnt, int align)
+{
+       u32 obj, i;
+
+       if (likely(cnt == 1 && align == 1))
+               return mlx4_bitmap_alloc(bitmap);
+
+       spin_lock(&bitmap->lock);
+
+       obj = find_aligned_range(bitmap->table, bitmap->last,
+                                bitmap->effective_max, cnt, align);
+       if (obj >= bitmap->effective_max) {
+               bitmap->top = (bitmap->top + bitmap->max) & bitmap->mask;
+               obj = find_aligned_range(bitmap->table, 0,
+                                        bitmap->effective_max,
+                                        cnt, align);
+       }
+
+       if (obj < bitmap->effective_max) {
+               for (i = 0; i < cnt; i++)
+                       set_bit(obj+i, bitmap->table);
+               if (obj == bitmap->last) {
+                       bitmap->last = (obj + cnt);
+                       if (bitmap->last >= bitmap->effective_max)
+                               bitmap->last = 0;
+               }
+               obj |= bitmap->top;
+       } else
+               obj = -1;
+
+       spin_unlock(&bitmap->lock);
+
+       return obj;
+}
+
+void mlx4_bitmap_free_range(struct mlx4_bitmap *bitmap, u32 obj, int cnt)
+{
+       u32 i;
+
+       obj &= bitmap->max - 1;
+
+       spin_lock(&bitmap->lock);
+       for (i = 0; i < cnt; i++)
+               clear_bit(obj+i, bitmap->table);
+       bitmap->last = min(bitmap->last, obj);
+       bitmap->top = (bitmap->top + bitmap->max) & bitmap->mask;
+       spin_unlock(&bitmap->lock);
+}
+
+int mlx4_bitmap_init_with_effective_max(struct mlx4_bitmap *bitmap,
+                                       u32 num, u32 mask, u32 reserved,
+                                       u32 effective_max)
 {
        int i;

@@ -85,6 +164,7 @@ int mlx4_bitmap_init(struct mlx4_bitmap *bitmap, u32 num, 
u32 mask, u32 reserved
        bitmap->top  = 0;
        bitmap->max  = num;
        bitmap->mask = mask;
+       bitmap->effective_max = effective_max;
        spin_lock_init(&bitmap->lock);
        bitmap->table = kzalloc(BITS_TO_LONGS(num) * sizeof (long), GFP_KERNEL);
        if (!bitmap->table)
@@ -96,6 +176,13 @@ int mlx4_bitmap_init(struct mlx4_bitmap *bitmap, u32 num, 
u32 mask, u32 reserved
        return 0;
 }

+int mlx4_bitmap_init(struct mlx4_bitmap *bitmap,
+                    u32 num, u32 mask, u32 reserved)
+{
+       return mlx4_bitmap_init_with_effective_max(bitmap, num, mask,
+                                                  reserved, num);
+}
+
 void mlx4_bitmap_cleanup(struct mlx4_bitmap *bitmap)
 {
        kfree(bitmap->table);
diff --git a/drivers/net/mlx4/mlx4.h b/drivers/net/mlx4/mlx4.h
index a4023c2..2c69d46 100644
--- a/drivers/net/mlx4/mlx4.h
+++ b/drivers/net/mlx4/mlx4.h
@@ -111,6 +111,7 @@ struct mlx4_bitmap {
        u32                     last;
        u32                     top;
        u32                     max;
+       u32                     effective_max;
        u32                     mask;
        spinlock_t              lock;
        unsigned long          *table;
@@ -287,7 +288,12 @@ static inline struct mlx4_priv *mlx4_priv(struct mlx4_dev 
*dev)

 u32 mlx4_bitmap_alloc(struct mlx4_bitmap *bitmap);
 void mlx4_bitmap_free(struct mlx4_bitmap *bitmap, u32 obj);
+u32 mlx4_bitmap_alloc_range(struct mlx4_bitmap *bitmap, int cnt, int align);
+void mlx4_bitmap_free_range(struct mlx4_bitmap *bitmap, u32 obj, int cnt);
 int mlx4_bitmap_init(struct mlx4_bitmap *bitmap, u32 num, u32 mask, u32 
reserved);
+int mlx4_bitmap_init_with_effective_max(struct mlx4_bitmap *bitmap,
+                                       u32 num, u32 mask, u32 reserved,
+                                       u32 effective_max);
 void mlx4_bitmap_cleanup(struct mlx4_bitmap *bitmap);

 int mlx4_reset(struct mlx4_dev *dev);
diff --git a/drivers/net/mlx4/qp.c b/drivers/net/mlx4/qp.c
index fa24e65..dff8e66 100644
--- a/drivers/net/mlx4/qp.c
+++ b/drivers/net/mlx4/qp.c
@@ -147,19 +147,42 @@ int mlx4_qp_modify(struct mlx4_dev *dev, struct mlx4_mtt 
*mtt,
 }
 EXPORT_SYMBOL_GPL(mlx4_qp_modify);

-int mlx4_qp_alloc(struct mlx4_dev *dev, int sqpn, struct mlx4_qp *qp)
+int mlx4_qp_reserve_range(struct mlx4_dev *dev, int cnt, int align, int *base)
+{
+       struct mlx4_priv *priv = mlx4_priv(dev);
+       struct mlx4_qp_table *qp_table = &priv->qp_table;
+       int qpn;
+
+       qpn = mlx4_bitmap_alloc_range(&qp_table->bitmap, cnt, align);
+       if (qpn == -1)
+               return -ENOMEM;
+
+       *base = qpn;
+       return 0;
+}
+EXPORT_SYMBOL_GPL(mlx4_qp_reserve_range);
+
+void mlx4_qp_release_range(struct mlx4_dev *dev, int base_qpn, int cnt)
+{
+       struct mlx4_priv *priv = mlx4_priv(dev);
+       struct mlx4_qp_table *qp_table = &priv->qp_table;
+       if (base_qpn < dev->caps.sqp_start + 8)
+               return;
+
+       mlx4_bitmap_free_range(&qp_table->bitmap, base_qpn, cnt);
+}
+EXPORT_SYMBOL_GPL(mlx4_qp_release_range);
+
+int mlx4_qp_alloc(struct mlx4_dev *dev, int qpn, struct mlx4_qp *qp)
 {
        struct mlx4_priv *priv = mlx4_priv(dev);
        struct mlx4_qp_table *qp_table = &priv->qp_table;
        int err;

-       if (sqpn)
-               qp->qpn = sqpn;
-       else {
-               qp->qpn = mlx4_bitmap_alloc(&qp_table->bitmap);
-               if (qp->qpn == -1)
-                       return -ENOMEM;
-       }
+       if (!qpn)
+               return -EINVAL;
+
+       qp->qpn = qpn;

        err = mlx4_table_get(dev, &qp_table->qp_table, qp->qpn);
        if (err)
@@ -208,9 +231,6 @@ err_put_qp:
        mlx4_table_put(dev, &qp_table->qp_table, qp->qpn);

 err_out:
-       if (!sqpn)
-               mlx4_bitmap_free(&qp_table->bitmap, qp->qpn);
-
        return err;
 }
 EXPORT_SYMBOL_GPL(mlx4_qp_alloc);
@@ -240,8 +260,6 @@ void mlx4_qp_free(struct mlx4_dev *dev, struct mlx4_qp *qp)
        mlx4_table_put(dev, &qp_table->auxc_table, qp->qpn);
        mlx4_table_put(dev, &qp_table->qp_table, qp->qpn);

-       if (qp->qpn >= dev->caps.sqp_start + 8)
-               mlx4_bitmap_free(&qp_table->bitmap, qp->qpn);
 }
 EXPORT_SYMBOL_GPL(mlx4_qp_free);

diff --git a/include/linux/mlx4/device.h b/include/linux/mlx4/device.h
index 0cb92ee..a088c63 100644
--- a/include/linux/mlx4/device.h
+++ b/include/linux/mlx4/device.h
@@ -395,7 +395,10 @@ int mlx4_cq_alloc(struct mlx4_dev *dev, int nent, struct 
mlx4_mtt *mtt,
                  struct mlx4_uar *uar, u64 db_rec, struct mlx4_cq *cq);
 void mlx4_cq_free(struct mlx4_dev *dev, struct mlx4_cq *cq);

-int mlx4_qp_alloc(struct mlx4_dev *dev, int sqpn, struct mlx4_qp *qp);
+int mlx4_qp_reserve_range(struct mlx4_dev *dev, int cnt, int align, int *base);
+void mlx4_qp_release_range(struct mlx4_dev *dev, int base_qpn, int cnt);
+
+int mlx4_qp_alloc(struct mlx4_dev *dev, int qpn, struct mlx4_qp *qp);
 void mlx4_qp_free(struct mlx4_dev *dev, struct mlx4_qp *qp);

 int mlx4_srq_alloc(struct mlx4_dev *dev, u32 pdn, struct mlx4_mtt *mtt,
-- 
1.5.4

_______________________________________________
general mailing list
[email protected]
http://lists.openfabrics.org/cgi-bin/mailman/listinfo/general

To unsubscribe, please visit http://openib.org/mailman/listinfo/openib-general

Reply via email to