diff options
-rw-r--r-- | drivers/infiniband/hw/mlx4/qp.c | 21 | ||||
-rw-r--r-- | drivers/net/mlx4/alloc.c | 74 | ||||
-rw-r--r-- | drivers/net/mlx4/mlx4.h | 2 | ||||
-rw-r--r-- | drivers/net/mlx4/qp.c | 45 | ||||
-rw-r--r-- | include/linux/mlx4/device.h | 5 |
5 files changed, 129 insertions, 18 deletions
diff --git a/drivers/infiniband/hw/mlx4/qp.c b/drivers/infiniband/hw/mlx4/qp.c index baa01deb2436..39167a797f99 100644 --- a/drivers/infiniband/hw/mlx4/qp.c +++ b/drivers/infiniband/hw/mlx4/qp.c | |||
@@ -451,6 +451,7 @@ static int create_qp_common(struct mlx4_ib_dev *dev, struct ib_pd *pd, | |||
451 | struct ib_qp_init_attr *init_attr, | 451 | struct ib_qp_init_attr *init_attr, |
452 | struct ib_udata *udata, int sqpn, struct mlx4_ib_qp *qp) | 452 | struct ib_udata *udata, int sqpn, struct mlx4_ib_qp *qp) |
453 | { | 453 | { |
454 | int qpn; | ||
454 | int err; | 455 | int err; |
455 | 456 | ||
456 | mutex_init(&qp->mutex); | 457 | mutex_init(&qp->mutex); |
@@ -545,9 +546,17 @@ static int create_qp_common(struct mlx4_ib_dev *dev, struct ib_pd *pd, | |||
545 | } | 546 | } |
546 | } | 547 | } |
547 | 548 | ||
548 | err = mlx4_qp_alloc(dev->dev, sqpn, &qp->mqp); | 549 | if (sqpn) { |
550 | qpn = sqpn; | ||
551 | } else { | ||
552 | err = mlx4_qp_reserve_range(dev->dev, 1, 1, &qpn); | ||
553 | if (err) | ||
554 | goto err_wrid; | ||
555 | } | ||
556 | |||
557 | err = mlx4_qp_alloc(dev->dev, qpn, &qp->mqp); | ||
549 | if (err) | 558 | if (err) |
550 | goto err_wrid; | 559 | goto err_qpn; |
551 | 560 | ||
552 | /* | 561 | /* |
553 | * Hardware wants QPN written in big-endian order (after | 562 | * Hardware wants QPN written in big-endian order (after |
@@ -560,6 +569,10 @@ static int create_qp_common(struct mlx4_ib_dev *dev, struct ib_pd *pd, | |||
560 | 569 | ||
561 | return 0; | 570 | return 0; |
562 | 571 | ||
572 | err_qpn: | ||
573 | if (!sqpn) | ||
574 | mlx4_qp_release_range(dev->dev, qpn, 1); | ||
575 | |||
563 | err_wrid: | 576 | err_wrid: |
564 | if (pd->uobject) { | 577 | if (pd->uobject) { |
565 | if (!init_attr->srq) | 578 | if (!init_attr->srq) |
@@ -655,6 +668,10 @@ static void destroy_qp_common(struct mlx4_ib_dev *dev, struct mlx4_ib_qp *qp, | |||
655 | mlx4_ib_unlock_cqs(send_cq, recv_cq); | 668 | mlx4_ib_unlock_cqs(send_cq, recv_cq); |
656 | 669 | ||
657 | mlx4_qp_free(dev->dev, &qp->mqp); | 670 | mlx4_qp_free(dev->dev, &qp->mqp); |
671 | |||
672 | if (!is_sqp(dev, qp)) | ||
673 | mlx4_qp_release_range(dev->dev, qp->mqp.qpn, 1); | ||
674 | |||
658 | mlx4_mtt_cleanup(dev->dev, &qp->mtt); | 675 | mlx4_mtt_cleanup(dev->dev, &qp->mtt); |
659 | 676 | ||
660 | if (is_user) { | 677 | if (is_user) { |
diff --git a/drivers/net/mlx4/alloc.c b/drivers/net/mlx4/alloc.c index 096bca54bcf7..e6c0d5bb5dcb 100644 --- a/drivers/net/mlx4/alloc.c +++ b/drivers/net/mlx4/alloc.c | |||
@@ -65,10 +65,82 @@ u32 mlx4_bitmap_alloc(struct mlx4_bitmap *bitmap) | |||
65 | 65 | ||
66 | void mlx4_bitmap_free(struct mlx4_bitmap *bitmap, u32 obj) | 66 | void mlx4_bitmap_free(struct mlx4_bitmap *bitmap, u32 obj) |
67 | { | 67 | { |
68 | mlx4_bitmap_free_range(bitmap, obj, 1); | ||
69 | } | ||
70 | |||
71 | static unsigned long find_aligned_range(unsigned long *bitmap, | ||
72 | u32 start, u32 nbits, | ||
73 | int len, int align) | ||
74 | { | ||
75 | unsigned long end, i; | ||
76 | |||
77 | again: | ||
78 | start = ALIGN(start, align); | ||
79 | |||
80 | while ((start < nbits) && test_bit(start, bitmap)) | ||
81 | start += align; | ||
82 | |||
83 | if (start >= nbits) | ||
84 | return -1; | ||
85 | |||
86 | end = start+len; | ||
87 | if (end > nbits) | ||
88 | return -1; | ||
89 | |||
90 | for (i = start + 1; i < end; i++) { | ||
91 | if (test_bit(i, bitmap)) { | ||
92 | start = i + 1; | ||
93 | goto again; | ||
94 | } | ||
95 | } | ||
96 | |||
97 | return start; | ||
98 | } | ||
99 | |||
100 | u32 mlx4_bitmap_alloc_range(struct mlx4_bitmap *bitmap, int cnt, int align) | ||
101 | { | ||
102 | u32 obj, i; | ||
103 | |||
104 | if (likely(cnt == 1 && align == 1)) | ||
105 | return mlx4_bitmap_alloc(bitmap); | ||
106 | |||
107 | spin_lock(&bitmap->lock); | ||
108 | |||
109 | obj = find_aligned_range(bitmap->table, bitmap->last, | ||
110 | bitmap->max, cnt, align); | ||
111 | if (obj >= bitmap->max) { | ||
112 | bitmap->top = (bitmap->top + bitmap->max) & bitmap->mask; | ||
113 | obj = find_aligned_range(bitmap->table, 0, | ||
114 | bitmap->max, | ||
115 | cnt, align); | ||
116 | } | ||
117 | |||
118 | if (obj < bitmap->max) { | ||
119 | for (i = 0; i < cnt; i++) | ||
120 | set_bit(obj + i, bitmap->table); | ||
121 | if (obj == bitmap->last) { | ||
122 | bitmap->last = (obj + cnt); | ||
123 | if (bitmap->last >= bitmap->max) | ||
124 | bitmap->last = 0; | ||
125 | } | ||
126 | obj |= bitmap->top; | ||
127 | } else | ||
128 | obj = -1; | ||
129 | |||
130 | spin_unlock(&bitmap->lock); | ||
131 | |||
132 | return obj; | ||
133 | } | ||
134 | |||
135 | void mlx4_bitmap_free_range(struct mlx4_bitmap *bitmap, u32 obj, int cnt) | ||
136 | { | ||
137 | u32 i; | ||
138 | |||
68 | obj &= bitmap->max - 1; | 139 | obj &= bitmap->max - 1; |
69 | 140 | ||
70 | spin_lock(&bitmap->lock); | 141 | spin_lock(&bitmap->lock); |
71 | clear_bit(obj, bitmap->table); | 142 | for (i = 0; i < cnt; i++) |
143 | clear_bit(obj + i, bitmap->table); | ||
72 | bitmap->last = min(bitmap->last, obj); | 144 | bitmap->last = min(bitmap->last, obj); |
73 | bitmap->top = (bitmap->top + bitmap->max) & bitmap->mask; | 145 | bitmap->top = (bitmap->top + bitmap->max) & bitmap->mask; |
74 | spin_unlock(&bitmap->lock); | 146 | spin_unlock(&bitmap->lock); |
diff --git a/drivers/net/mlx4/mlx4.h b/drivers/net/mlx4/mlx4.h index 5337e3ac3e78..b55ddab73f66 100644 --- a/drivers/net/mlx4/mlx4.h +++ b/drivers/net/mlx4/mlx4.h | |||
@@ -288,6 +288,8 @@ static inline struct mlx4_priv *mlx4_priv(struct mlx4_dev *dev) | |||
288 | 288 | ||
289 | u32 mlx4_bitmap_alloc(struct mlx4_bitmap *bitmap); | 289 | u32 mlx4_bitmap_alloc(struct mlx4_bitmap *bitmap); |
290 | void mlx4_bitmap_free(struct mlx4_bitmap *bitmap, u32 obj); | 290 | void mlx4_bitmap_free(struct mlx4_bitmap *bitmap, u32 obj); |
291 | u32 mlx4_bitmap_alloc_range(struct mlx4_bitmap *bitmap, int cnt, int align); | ||
292 | void mlx4_bitmap_free_range(struct mlx4_bitmap *bitmap, u32 obj, int cnt); | ||
291 | int mlx4_bitmap_init(struct mlx4_bitmap *bitmap, u32 num, u32 mask, u32 reserved); | 293 | int mlx4_bitmap_init(struct mlx4_bitmap *bitmap, u32 num, u32 mask, u32 reserved); |
292 | void mlx4_bitmap_cleanup(struct mlx4_bitmap *bitmap); | 294 | void mlx4_bitmap_cleanup(struct mlx4_bitmap *bitmap); |
293 | 295 | ||
diff --git a/drivers/net/mlx4/qp.c b/drivers/net/mlx4/qp.c index c49a86044bf7..98e0c40ba368 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, | |||
147 | } | 147 | } |
148 | EXPORT_SYMBOL_GPL(mlx4_qp_modify); | 148 | EXPORT_SYMBOL_GPL(mlx4_qp_modify); |
149 | 149 | ||
150 | int mlx4_qp_alloc(struct mlx4_dev *dev, int sqpn, struct mlx4_qp *qp) | 150 | int mlx4_qp_reserve_range(struct mlx4_dev *dev, int cnt, int align, int *base) |
151 | { | ||
152 | struct mlx4_priv *priv = mlx4_priv(dev); | ||
153 | struct mlx4_qp_table *qp_table = &priv->qp_table; | ||
154 | int qpn; | ||
155 | |||
156 | qpn = mlx4_bitmap_alloc_range(&qp_table->bitmap, cnt, align); | ||
157 | if (qpn == -1) | ||
158 | return -ENOMEM; | ||
159 | |||
160 | *base = qpn; | ||
161 | return 0; | ||
162 | } | ||
163 | EXPORT_SYMBOL_GPL(mlx4_qp_reserve_range); | ||
164 | |||
165 | void mlx4_qp_release_range(struct mlx4_dev *dev, int base_qpn, int cnt) | ||
166 | { | ||
167 | struct mlx4_priv *priv = mlx4_priv(dev); | ||
168 | struct mlx4_qp_table *qp_table = &priv->qp_table; | ||
169 | if (base_qpn < dev->caps.sqp_start + 8) | ||
170 | return; | ||
171 | |||
172 | mlx4_bitmap_free_range(&qp_table->bitmap, base_qpn, cnt); | ||
173 | } | ||
174 | EXPORT_SYMBOL_GPL(mlx4_qp_release_range); | ||
175 | |||
176 | int mlx4_qp_alloc(struct mlx4_dev *dev, int qpn, struct mlx4_qp *qp) | ||
151 | { | 177 | { |
152 | struct mlx4_priv *priv = mlx4_priv(dev); | 178 | struct mlx4_priv *priv = mlx4_priv(dev); |
153 | struct mlx4_qp_table *qp_table = &priv->qp_table; | 179 | struct mlx4_qp_table *qp_table = &priv->qp_table; |
154 | int err; | 180 | int err; |
155 | 181 | ||
156 | if (sqpn) | 182 | if (!qpn) |
157 | qp->qpn = sqpn; | 183 | return -EINVAL; |
158 | else { | 184 | |
159 | qp->qpn = mlx4_bitmap_alloc(&qp_table->bitmap); | 185 | qp->qpn = qpn; |
160 | if (qp->qpn == -1) | ||
161 | return -ENOMEM; | ||
162 | } | ||
163 | 186 | ||
164 | err = mlx4_table_get(dev, &qp_table->qp_table, qp->qpn); | 187 | err = mlx4_table_get(dev, &qp_table->qp_table, qp->qpn); |
165 | if (err) | 188 | if (err) |
@@ -208,9 +231,6 @@ err_put_qp: | |||
208 | mlx4_table_put(dev, &qp_table->qp_table, qp->qpn); | 231 | mlx4_table_put(dev, &qp_table->qp_table, qp->qpn); |
209 | 232 | ||
210 | err_out: | 233 | err_out: |
211 | if (!sqpn) | ||
212 | mlx4_bitmap_free(&qp_table->bitmap, qp->qpn); | ||
213 | |||
214 | return err; | 234 | return err; |
215 | } | 235 | } |
216 | EXPORT_SYMBOL_GPL(mlx4_qp_alloc); | 236 | EXPORT_SYMBOL_GPL(mlx4_qp_alloc); |
@@ -239,9 +259,6 @@ void mlx4_qp_free(struct mlx4_dev *dev, struct mlx4_qp *qp) | |||
239 | mlx4_table_put(dev, &qp_table->altc_table, qp->qpn); | 259 | mlx4_table_put(dev, &qp_table->altc_table, qp->qpn); |
240 | mlx4_table_put(dev, &qp_table->auxc_table, qp->qpn); | 260 | mlx4_table_put(dev, &qp_table->auxc_table, qp->qpn); |
241 | mlx4_table_put(dev, &qp_table->qp_table, qp->qpn); | 261 | mlx4_table_put(dev, &qp_table->qp_table, qp->qpn); |
242 | |||
243 | if (qp->qpn >= dev->caps.sqp_start + 8) | ||
244 | mlx4_bitmap_free(&qp_table->bitmap, qp->qpn); | ||
245 | } | 262 | } |
246 | EXPORT_SYMBOL_GPL(mlx4_qp_free); | 263 | EXPORT_SYMBOL_GPL(mlx4_qp_free); |
247 | 264 | ||
diff --git a/include/linux/mlx4/device.h b/include/linux/mlx4/device.h index b2f944468313..d21e879f3c90 100644 --- a/include/linux/mlx4/device.h +++ b/include/linux/mlx4/device.h | |||
@@ -400,7 +400,10 @@ int mlx4_cq_alloc(struct mlx4_dev *dev, int nent, struct mlx4_mtt *mtt, | |||
400 | int collapsed); | 400 | int collapsed); |
401 | void mlx4_cq_free(struct mlx4_dev *dev, struct mlx4_cq *cq); | 401 | void mlx4_cq_free(struct mlx4_dev *dev, struct mlx4_cq *cq); |
402 | 402 | ||
403 | int mlx4_qp_alloc(struct mlx4_dev *dev, int sqpn, struct mlx4_qp *qp); | 403 | int mlx4_qp_reserve_range(struct mlx4_dev *dev, int cnt, int align, int *base); |
404 | void mlx4_qp_release_range(struct mlx4_dev *dev, int base_qpn, int cnt); | ||
405 | |||
406 | int mlx4_qp_alloc(struct mlx4_dev *dev, int qpn, struct mlx4_qp *qp); | ||
404 | void mlx4_qp_free(struct mlx4_dev *dev, struct mlx4_qp *qp); | 407 | void mlx4_qp_free(struct mlx4_dev *dev, struct mlx4_qp *qp); |
405 | 408 | ||
406 | int mlx4_srq_alloc(struct mlx4_dev *dev, u32 pdn, struct mlx4_mtt *mtt, | 409 | int mlx4_srq_alloc(struct mlx4_dev *dev, u32 pdn, struct mlx4_mtt *mtt, |