1*d6b92ffaSHans Petter Selasky /*
2*d6b92ffaSHans Petter Selasky * Copyright (c) 2012 Mellanox Technologies, Inc. All rights reserved.
3*d6b92ffaSHans Petter Selasky *
4*d6b92ffaSHans Petter Selasky * This software is available to you under a choice of one of two
5*d6b92ffaSHans Petter Selasky * licenses. You may choose to be licensed under the terms of the GNU
6*d6b92ffaSHans Petter Selasky * General Public License (GPL) Version 2, available from the file
7*d6b92ffaSHans Petter Selasky * COPYING in the main directory of this source tree, or the
8*d6b92ffaSHans Petter Selasky * OpenIB.org BSD license below:
9*d6b92ffaSHans Petter Selasky *
10*d6b92ffaSHans Petter Selasky * Redistribution and use in source and binary forms, with or
11*d6b92ffaSHans Petter Selasky * without modification, are permitted provided that the following
12*d6b92ffaSHans Petter Selasky * conditions are met:
13*d6b92ffaSHans Petter Selasky *
14*d6b92ffaSHans Petter Selasky * - Redistributions of source code must retain the above
15*d6b92ffaSHans Petter Selasky * copyright notice, this list of conditions and the following
16*d6b92ffaSHans Petter Selasky * disclaimer.
17*d6b92ffaSHans Petter Selasky *
18*d6b92ffaSHans Petter Selasky * - Redistributions in binary form must reproduce the above
19*d6b92ffaSHans Petter Selasky * copyright notice, this list of conditions and the following
20*d6b92ffaSHans Petter Selasky * disclaimer in the documentation and/or other materials
21*d6b92ffaSHans Petter Selasky * provided with the distribution.
22*d6b92ffaSHans Petter Selasky *
23*d6b92ffaSHans Petter Selasky * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
24*d6b92ffaSHans Petter Selasky * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
25*d6b92ffaSHans Petter Selasky * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
26*d6b92ffaSHans Petter Selasky * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
27*d6b92ffaSHans Petter Selasky * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
28*d6b92ffaSHans Petter Selasky * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
29*d6b92ffaSHans Petter Selasky * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
30*d6b92ffaSHans Petter Selasky * SOFTWARE.
31*d6b92ffaSHans Petter Selasky */
32*d6b92ffaSHans Petter Selasky
33*d6b92ffaSHans Petter Selasky #include <config.h>
34*d6b92ffaSHans Petter Selasky
35*d6b92ffaSHans Petter Selasky #include <signal.h>
36*d6b92ffaSHans Petter Selasky #include <sys/ipc.h>
37*d6b92ffaSHans Petter Selasky #include <sys/shm.h>
38*d6b92ffaSHans Petter Selasky #include <stdio.h>
39*d6b92ffaSHans Petter Selasky #include <stdlib.h>
40*d6b92ffaSHans Petter Selasky #include <errno.h>
41*d6b92ffaSHans Petter Selasky
42*d6b92ffaSHans Petter Selasky #include "mlx5.h"
43*d6b92ffaSHans Petter Selasky #include "bitmap.h"
44*d6b92ffaSHans Petter Selasky
mlx5_bitmap_init(struct mlx5_bitmap * bitmap,uint32_t num,uint32_t mask)45*d6b92ffaSHans Petter Selasky static int mlx5_bitmap_init(struct mlx5_bitmap *bitmap, uint32_t num,
46*d6b92ffaSHans Petter Selasky uint32_t mask)
47*d6b92ffaSHans Petter Selasky {
48*d6b92ffaSHans Petter Selasky bitmap->last = 0;
49*d6b92ffaSHans Petter Selasky bitmap->top = 0;
50*d6b92ffaSHans Petter Selasky bitmap->max = num;
51*d6b92ffaSHans Petter Selasky bitmap->avail = num;
52*d6b92ffaSHans Petter Selasky bitmap->mask = mask;
53*d6b92ffaSHans Petter Selasky bitmap->avail = bitmap->max;
54*d6b92ffaSHans Petter Selasky bitmap->table = calloc(BITS_TO_LONGS(bitmap->max), sizeof(uint32_t));
55*d6b92ffaSHans Petter Selasky if (!bitmap->table)
56*d6b92ffaSHans Petter Selasky return -ENOMEM;
57*d6b92ffaSHans Petter Selasky
58*d6b92ffaSHans Petter Selasky return 0;
59*d6b92ffaSHans Petter Selasky }
60*d6b92ffaSHans Petter Selasky
bitmap_free_range(struct mlx5_bitmap * bitmap,uint32_t obj,int cnt)61*d6b92ffaSHans Petter Selasky static void bitmap_free_range(struct mlx5_bitmap *bitmap, uint32_t obj,
62*d6b92ffaSHans Petter Selasky int cnt)
63*d6b92ffaSHans Petter Selasky {
64*d6b92ffaSHans Petter Selasky int i;
65*d6b92ffaSHans Petter Selasky
66*d6b92ffaSHans Petter Selasky obj &= bitmap->max - 1;
67*d6b92ffaSHans Petter Selasky
68*d6b92ffaSHans Petter Selasky for (i = 0; i < cnt; i++)
69*d6b92ffaSHans Petter Selasky mlx5_clear_bit(obj + i, bitmap->table);
70*d6b92ffaSHans Petter Selasky bitmap->last = min(bitmap->last, obj);
71*d6b92ffaSHans Petter Selasky bitmap->top = (bitmap->top + bitmap->max) & bitmap->mask;
72*d6b92ffaSHans Petter Selasky bitmap->avail += cnt;
73*d6b92ffaSHans Petter Selasky }
74*d6b92ffaSHans Petter Selasky
bitmap_empty(struct mlx5_bitmap * bitmap)75*d6b92ffaSHans Petter Selasky static int bitmap_empty(struct mlx5_bitmap *bitmap)
76*d6b92ffaSHans Petter Selasky {
77*d6b92ffaSHans Petter Selasky return (bitmap->avail == bitmap->max) ? 1 : 0;
78*d6b92ffaSHans Petter Selasky }
79*d6b92ffaSHans Petter Selasky
bitmap_avail(struct mlx5_bitmap * bitmap)80*d6b92ffaSHans Petter Selasky static int bitmap_avail(struct mlx5_bitmap *bitmap)
81*d6b92ffaSHans Petter Selasky {
82*d6b92ffaSHans Petter Selasky return bitmap->avail;
83*d6b92ffaSHans Petter Selasky }
84*d6b92ffaSHans Petter Selasky
mlx5_bitmap_cleanup(struct mlx5_bitmap * bitmap)85*d6b92ffaSHans Petter Selasky static void mlx5_bitmap_cleanup(struct mlx5_bitmap *bitmap)
86*d6b92ffaSHans Petter Selasky {
87*d6b92ffaSHans Petter Selasky if (bitmap->table)
88*d6b92ffaSHans Petter Selasky free(bitmap->table);
89*d6b92ffaSHans Petter Selasky }
90*d6b92ffaSHans Petter Selasky
free_huge_mem(struct mlx5_hugetlb_mem * hmem)91*d6b92ffaSHans Petter Selasky static void free_huge_mem(struct mlx5_hugetlb_mem *hmem)
92*d6b92ffaSHans Petter Selasky {
93*d6b92ffaSHans Petter Selasky mlx5_bitmap_cleanup(&hmem->bitmap);
94*d6b92ffaSHans Petter Selasky if (shmdt(hmem->shmaddr) == -1)
95*d6b92ffaSHans Petter Selasky mlx5_dbg(stderr, MLX5_DBG_CONTIG, "%s\n", strerror(errno));
96*d6b92ffaSHans Petter Selasky shmctl(hmem->shmid, IPC_RMID, NULL);
97*d6b92ffaSHans Petter Selasky free(hmem);
98*d6b92ffaSHans Petter Selasky }
99*d6b92ffaSHans Petter Selasky
mlx5_bitmap_alloc(struct mlx5_bitmap * bitmap)100*d6b92ffaSHans Petter Selasky static int mlx5_bitmap_alloc(struct mlx5_bitmap *bitmap)
101*d6b92ffaSHans Petter Selasky {
102*d6b92ffaSHans Petter Selasky uint32_t obj;
103*d6b92ffaSHans Petter Selasky int ret;
104*d6b92ffaSHans Petter Selasky
105*d6b92ffaSHans Petter Selasky obj = mlx5_find_first_zero_bit(bitmap->table, bitmap->max);
106*d6b92ffaSHans Petter Selasky if (obj < bitmap->max) {
107*d6b92ffaSHans Petter Selasky mlx5_set_bit(obj, bitmap->table);
108*d6b92ffaSHans Petter Selasky bitmap->last = (obj + 1);
109*d6b92ffaSHans Petter Selasky if (bitmap->last == bitmap->max)
110*d6b92ffaSHans Petter Selasky bitmap->last = 0;
111*d6b92ffaSHans Petter Selasky obj |= bitmap->top;
112*d6b92ffaSHans Petter Selasky ret = obj;
113*d6b92ffaSHans Petter Selasky } else
114*d6b92ffaSHans Petter Selasky ret = -1;
115*d6b92ffaSHans Petter Selasky
116*d6b92ffaSHans Petter Selasky if (ret != -1)
117*d6b92ffaSHans Petter Selasky --bitmap->avail;
118*d6b92ffaSHans Petter Selasky
119*d6b92ffaSHans Petter Selasky return ret;
120*d6b92ffaSHans Petter Selasky }
121*d6b92ffaSHans Petter Selasky
find_aligned_range(unsigned long * bitmap,uint32_t start,uint32_t nbits,int len,int alignment)122*d6b92ffaSHans Petter Selasky static uint32_t find_aligned_range(unsigned long *bitmap,
123*d6b92ffaSHans Petter Selasky uint32_t start, uint32_t nbits,
124*d6b92ffaSHans Petter Selasky int len, int alignment)
125*d6b92ffaSHans Petter Selasky {
126*d6b92ffaSHans Petter Selasky uint32_t end, i;
127*d6b92ffaSHans Petter Selasky
128*d6b92ffaSHans Petter Selasky again:
129*d6b92ffaSHans Petter Selasky start = align(start, alignment);
130*d6b92ffaSHans Petter Selasky
131*d6b92ffaSHans Petter Selasky while ((start < nbits) && mlx5_test_bit(start, bitmap))
132*d6b92ffaSHans Petter Selasky start += alignment;
133*d6b92ffaSHans Petter Selasky
134*d6b92ffaSHans Petter Selasky if (start >= nbits)
135*d6b92ffaSHans Petter Selasky return -1;
136*d6b92ffaSHans Petter Selasky
137*d6b92ffaSHans Petter Selasky end = start + len;
138*d6b92ffaSHans Petter Selasky if (end > nbits)
139*d6b92ffaSHans Petter Selasky return -1;
140*d6b92ffaSHans Petter Selasky
141*d6b92ffaSHans Petter Selasky for (i = start + 1; i < end; i++) {
142*d6b92ffaSHans Petter Selasky if (mlx5_test_bit(i, bitmap)) {
143*d6b92ffaSHans Petter Selasky start = i + 1;
144*d6b92ffaSHans Petter Selasky goto again;
145*d6b92ffaSHans Petter Selasky }
146*d6b92ffaSHans Petter Selasky }
147*d6b92ffaSHans Petter Selasky
148*d6b92ffaSHans Petter Selasky return start;
149*d6b92ffaSHans Petter Selasky }
150*d6b92ffaSHans Petter Selasky
bitmap_alloc_range(struct mlx5_bitmap * bitmap,int cnt,int align)151*d6b92ffaSHans Petter Selasky static int bitmap_alloc_range(struct mlx5_bitmap *bitmap, int cnt,
152*d6b92ffaSHans Petter Selasky int align)
153*d6b92ffaSHans Petter Selasky {
154*d6b92ffaSHans Petter Selasky uint32_t obj;
155*d6b92ffaSHans Petter Selasky int ret, i;
156*d6b92ffaSHans Petter Selasky
157*d6b92ffaSHans Petter Selasky if (cnt == 1 && align == 1)
158*d6b92ffaSHans Petter Selasky return mlx5_bitmap_alloc(bitmap);
159*d6b92ffaSHans Petter Selasky
160*d6b92ffaSHans Petter Selasky if (cnt > bitmap->max)
161*d6b92ffaSHans Petter Selasky return -1;
162*d6b92ffaSHans Petter Selasky
163*d6b92ffaSHans Petter Selasky obj = find_aligned_range(bitmap->table, bitmap->last,
164*d6b92ffaSHans Petter Selasky bitmap->max, cnt, align);
165*d6b92ffaSHans Petter Selasky if (obj >= bitmap->max) {
166*d6b92ffaSHans Petter Selasky bitmap->top = (bitmap->top + bitmap->max) & bitmap->mask;
167*d6b92ffaSHans Petter Selasky obj = find_aligned_range(bitmap->table, 0, bitmap->max,
168*d6b92ffaSHans Petter Selasky cnt, align);
169*d6b92ffaSHans Petter Selasky }
170*d6b92ffaSHans Petter Selasky
171*d6b92ffaSHans Petter Selasky if (obj < bitmap->max) {
172*d6b92ffaSHans Petter Selasky for (i = 0; i < cnt; i++)
173*d6b92ffaSHans Petter Selasky mlx5_set_bit(obj + i, bitmap->table);
174*d6b92ffaSHans Petter Selasky if (obj == bitmap->last) {
175*d6b92ffaSHans Petter Selasky bitmap->last = (obj + cnt);
176*d6b92ffaSHans Petter Selasky if (bitmap->last >= bitmap->max)
177*d6b92ffaSHans Petter Selasky bitmap->last = 0;
178*d6b92ffaSHans Petter Selasky }
179*d6b92ffaSHans Petter Selasky obj |= bitmap->top;
180*d6b92ffaSHans Petter Selasky ret = obj;
181*d6b92ffaSHans Petter Selasky } else
182*d6b92ffaSHans Petter Selasky ret = -1;
183*d6b92ffaSHans Petter Selasky
184*d6b92ffaSHans Petter Selasky if (ret != -1)
185*d6b92ffaSHans Petter Selasky bitmap->avail -= cnt;
186*d6b92ffaSHans Petter Selasky
187*d6b92ffaSHans Petter Selasky return obj;
188*d6b92ffaSHans Petter Selasky }
189*d6b92ffaSHans Petter Selasky
alloc_huge_mem(size_t size)190*d6b92ffaSHans Petter Selasky static struct mlx5_hugetlb_mem *alloc_huge_mem(size_t size)
191*d6b92ffaSHans Petter Selasky {
192*d6b92ffaSHans Petter Selasky struct mlx5_hugetlb_mem *hmem;
193*d6b92ffaSHans Petter Selasky size_t shm_len;
194*d6b92ffaSHans Petter Selasky
195*d6b92ffaSHans Petter Selasky hmem = malloc(sizeof(*hmem));
196*d6b92ffaSHans Petter Selasky if (!hmem)
197*d6b92ffaSHans Petter Selasky return NULL;
198*d6b92ffaSHans Petter Selasky
199*d6b92ffaSHans Petter Selasky shm_len = align(size, MLX5_SHM_LENGTH);
200*d6b92ffaSHans Petter Selasky hmem->shmid = shmget(IPC_PRIVATE, shm_len, SHM_HUGETLB | SHM_R | SHM_W);
201*d6b92ffaSHans Petter Selasky if (hmem->shmid == -1) {
202*d6b92ffaSHans Petter Selasky mlx5_dbg(stderr, MLX5_DBG_CONTIG, "%s\n", strerror(errno));
203*d6b92ffaSHans Petter Selasky goto out_free;
204*d6b92ffaSHans Petter Selasky }
205*d6b92ffaSHans Petter Selasky
206*d6b92ffaSHans Petter Selasky hmem->shmaddr = shmat(hmem->shmid, MLX5_SHM_ADDR, MLX5_SHMAT_FLAGS);
207*d6b92ffaSHans Petter Selasky if (hmem->shmaddr == (void *)-1) {
208*d6b92ffaSHans Petter Selasky mlx5_dbg(stderr, MLX5_DBG_CONTIG, "%s\n", strerror(errno));
209*d6b92ffaSHans Petter Selasky goto out_rmid;
210*d6b92ffaSHans Petter Selasky }
211*d6b92ffaSHans Petter Selasky
212*d6b92ffaSHans Petter Selasky if (mlx5_bitmap_init(&hmem->bitmap, shm_len / MLX5_Q_CHUNK_SIZE,
213*d6b92ffaSHans Petter Selasky shm_len / MLX5_Q_CHUNK_SIZE - 1)) {
214*d6b92ffaSHans Petter Selasky mlx5_dbg(stderr, MLX5_DBG_CONTIG, "%s\n", strerror(errno));
215*d6b92ffaSHans Petter Selasky goto out_shmdt;
216*d6b92ffaSHans Petter Selasky }
217*d6b92ffaSHans Petter Selasky
218*d6b92ffaSHans Petter Selasky /*
219*d6b92ffaSHans Petter Selasky * Marked to be destroyed when process detaches from shmget segment
220*d6b92ffaSHans Petter Selasky */
221*d6b92ffaSHans Petter Selasky shmctl(hmem->shmid, IPC_RMID, NULL);
222*d6b92ffaSHans Petter Selasky
223*d6b92ffaSHans Petter Selasky return hmem;
224*d6b92ffaSHans Petter Selasky
225*d6b92ffaSHans Petter Selasky out_shmdt:
226*d6b92ffaSHans Petter Selasky if (shmdt(hmem->shmaddr) == -1)
227*d6b92ffaSHans Petter Selasky mlx5_dbg(stderr, MLX5_DBG_CONTIG, "%s\n", strerror(errno));
228*d6b92ffaSHans Petter Selasky
229*d6b92ffaSHans Petter Selasky out_rmid:
230*d6b92ffaSHans Petter Selasky shmctl(hmem->shmid, IPC_RMID, NULL);
231*d6b92ffaSHans Petter Selasky
232*d6b92ffaSHans Petter Selasky out_free:
233*d6b92ffaSHans Petter Selasky free(hmem);
234*d6b92ffaSHans Petter Selasky return NULL;
235*d6b92ffaSHans Petter Selasky }
236*d6b92ffaSHans Petter Selasky
alloc_huge_buf(struct mlx5_context * mctx,struct mlx5_buf * buf,size_t size,int page_size)237*d6b92ffaSHans Petter Selasky static int alloc_huge_buf(struct mlx5_context *mctx, struct mlx5_buf *buf,
238*d6b92ffaSHans Petter Selasky size_t size, int page_size)
239*d6b92ffaSHans Petter Selasky {
240*d6b92ffaSHans Petter Selasky int found = 0;
241*d6b92ffaSHans Petter Selasky int nchunk;
242*d6b92ffaSHans Petter Selasky struct mlx5_hugetlb_mem *hmem;
243*d6b92ffaSHans Petter Selasky int ret;
244*d6b92ffaSHans Petter Selasky
245*d6b92ffaSHans Petter Selasky buf->length = align(size, MLX5_Q_CHUNK_SIZE);
246*d6b92ffaSHans Petter Selasky nchunk = buf->length / MLX5_Q_CHUNK_SIZE;
247*d6b92ffaSHans Petter Selasky
248*d6b92ffaSHans Petter Selasky mlx5_spin_lock(&mctx->hugetlb_lock);
249*d6b92ffaSHans Petter Selasky TAILQ_FOREACH(hmem, &mctx->hugetlb_list, entry) {
250*d6b92ffaSHans Petter Selasky if (bitmap_avail(&hmem->bitmap)) {
251*d6b92ffaSHans Petter Selasky buf->base = bitmap_alloc_range(&hmem->bitmap, nchunk, 1);
252*d6b92ffaSHans Petter Selasky if (buf->base != -1) {
253*d6b92ffaSHans Petter Selasky buf->hmem = hmem;
254*d6b92ffaSHans Petter Selasky found = 1;
255*d6b92ffaSHans Petter Selasky break;
256*d6b92ffaSHans Petter Selasky }
257*d6b92ffaSHans Petter Selasky }
258*d6b92ffaSHans Petter Selasky }
259*d6b92ffaSHans Petter Selasky mlx5_spin_unlock(&mctx->hugetlb_lock);
260*d6b92ffaSHans Petter Selasky
261*d6b92ffaSHans Petter Selasky if (!found) {
262*d6b92ffaSHans Petter Selasky hmem = alloc_huge_mem(buf->length);
263*d6b92ffaSHans Petter Selasky if (!hmem)
264*d6b92ffaSHans Petter Selasky return -1;
265*d6b92ffaSHans Petter Selasky
266*d6b92ffaSHans Petter Selasky buf->base = bitmap_alloc_range(&hmem->bitmap, nchunk, 1);
267*d6b92ffaSHans Petter Selasky if (buf->base == -1) {
268*d6b92ffaSHans Petter Selasky free_huge_mem(hmem);
269*d6b92ffaSHans Petter Selasky /* TBD: remove after proven stability */
270*d6b92ffaSHans Petter Selasky fprintf(stderr, "BUG: huge allocation\n");
271*d6b92ffaSHans Petter Selasky return -1;
272*d6b92ffaSHans Petter Selasky }
273*d6b92ffaSHans Petter Selasky
274*d6b92ffaSHans Petter Selasky buf->hmem = hmem;
275*d6b92ffaSHans Petter Selasky
276*d6b92ffaSHans Petter Selasky mlx5_spin_lock(&mctx->hugetlb_lock);
277*d6b92ffaSHans Petter Selasky if (bitmap_avail(&hmem->bitmap))
278*d6b92ffaSHans Petter Selasky TAILQ_INSERT_HEAD(&mctx->hugetlb_list, hmem, entry);
279*d6b92ffaSHans Petter Selasky else
280*d6b92ffaSHans Petter Selasky TAILQ_INSERT_TAIL(&mctx->hugetlb_list, hmem, entry);
281*d6b92ffaSHans Petter Selasky mlx5_spin_unlock(&mctx->hugetlb_lock);
282*d6b92ffaSHans Petter Selasky }
283*d6b92ffaSHans Petter Selasky
284*d6b92ffaSHans Petter Selasky buf->buf = hmem->shmaddr + buf->base * MLX5_Q_CHUNK_SIZE;
285*d6b92ffaSHans Petter Selasky
286*d6b92ffaSHans Petter Selasky ret = ibv_dontfork_range(buf->buf, buf->length);
287*d6b92ffaSHans Petter Selasky if (ret) {
288*d6b92ffaSHans Petter Selasky mlx5_dbg(stderr, MLX5_DBG_CONTIG, "\n");
289*d6b92ffaSHans Petter Selasky goto out_fork;
290*d6b92ffaSHans Petter Selasky }
291*d6b92ffaSHans Petter Selasky buf->type = MLX5_ALLOC_TYPE_HUGE;
292*d6b92ffaSHans Petter Selasky
293*d6b92ffaSHans Petter Selasky return 0;
294*d6b92ffaSHans Petter Selasky
295*d6b92ffaSHans Petter Selasky out_fork:
296*d6b92ffaSHans Petter Selasky mlx5_spin_lock(&mctx->hugetlb_lock);
297*d6b92ffaSHans Petter Selasky bitmap_free_range(&hmem->bitmap, buf->base, nchunk);
298*d6b92ffaSHans Petter Selasky if (bitmap_empty(&hmem->bitmap)) {
299*d6b92ffaSHans Petter Selasky TAILQ_REMOVE(&mctx->hugetlb_list, hmem, entry);
300*d6b92ffaSHans Petter Selasky mlx5_spin_unlock(&mctx->hugetlb_lock);
301*d6b92ffaSHans Petter Selasky free_huge_mem(hmem);
302*d6b92ffaSHans Petter Selasky } else
303*d6b92ffaSHans Petter Selasky mlx5_spin_unlock(&mctx->hugetlb_lock);
304*d6b92ffaSHans Petter Selasky
305*d6b92ffaSHans Petter Selasky return -1;
306*d6b92ffaSHans Petter Selasky }
307*d6b92ffaSHans Petter Selasky
free_huge_buf(struct mlx5_context * ctx,struct mlx5_buf * buf)308*d6b92ffaSHans Petter Selasky static void free_huge_buf(struct mlx5_context *ctx, struct mlx5_buf *buf)
309*d6b92ffaSHans Petter Selasky {
310*d6b92ffaSHans Petter Selasky int nchunk;
311*d6b92ffaSHans Petter Selasky
312*d6b92ffaSHans Petter Selasky nchunk = buf->length / MLX5_Q_CHUNK_SIZE;
313*d6b92ffaSHans Petter Selasky mlx5_spin_lock(&ctx->hugetlb_lock);
314*d6b92ffaSHans Petter Selasky bitmap_free_range(&buf->hmem->bitmap, buf->base, nchunk);
315*d6b92ffaSHans Petter Selasky if (bitmap_empty(&buf->hmem->bitmap)) {
316*d6b92ffaSHans Petter Selasky TAILQ_REMOVE(&ctx->hugetlb_list, buf->hmem, entry);
317*d6b92ffaSHans Petter Selasky mlx5_spin_unlock(&ctx->hugetlb_lock);
318*d6b92ffaSHans Petter Selasky free_huge_mem(buf->hmem);
319*d6b92ffaSHans Petter Selasky } else
320*d6b92ffaSHans Petter Selasky mlx5_spin_unlock(&ctx->hugetlb_lock);
321*d6b92ffaSHans Petter Selasky }
322*d6b92ffaSHans Petter Selasky
mlx5_alloc_prefered_buf(struct mlx5_context * mctx,struct mlx5_buf * buf,size_t size,int page_size,enum mlx5_alloc_type type,const char * component)323*d6b92ffaSHans Petter Selasky int mlx5_alloc_prefered_buf(struct mlx5_context *mctx,
324*d6b92ffaSHans Petter Selasky struct mlx5_buf *buf,
325*d6b92ffaSHans Petter Selasky size_t size, int page_size,
326*d6b92ffaSHans Petter Selasky enum mlx5_alloc_type type,
327*d6b92ffaSHans Petter Selasky const char *component)
328*d6b92ffaSHans Petter Selasky {
329*d6b92ffaSHans Petter Selasky int ret;
330*d6b92ffaSHans Petter Selasky
331*d6b92ffaSHans Petter Selasky /*
332*d6b92ffaSHans Petter Selasky * Fallback mechanism priority:
333*d6b92ffaSHans Petter Selasky * huge pages
334*d6b92ffaSHans Petter Selasky * contig pages
335*d6b92ffaSHans Petter Selasky * default
336*d6b92ffaSHans Petter Selasky */
337*d6b92ffaSHans Petter Selasky if (type == MLX5_ALLOC_TYPE_HUGE ||
338*d6b92ffaSHans Petter Selasky type == MLX5_ALLOC_TYPE_PREFER_HUGE ||
339*d6b92ffaSHans Petter Selasky type == MLX5_ALLOC_TYPE_ALL) {
340*d6b92ffaSHans Petter Selasky ret = alloc_huge_buf(mctx, buf, size, page_size);
341*d6b92ffaSHans Petter Selasky if (!ret)
342*d6b92ffaSHans Petter Selasky return 0;
343*d6b92ffaSHans Petter Selasky
344*d6b92ffaSHans Petter Selasky if (type == MLX5_ALLOC_TYPE_HUGE)
345*d6b92ffaSHans Petter Selasky return -1;
346*d6b92ffaSHans Petter Selasky
347*d6b92ffaSHans Petter Selasky mlx5_dbg(stderr, MLX5_DBG_CONTIG,
348*d6b92ffaSHans Petter Selasky "Huge mode allocation failed, fallback to %s mode\n",
349*d6b92ffaSHans Petter Selasky MLX5_ALLOC_TYPE_ALL ? "contig" : "default");
350*d6b92ffaSHans Petter Selasky }
351*d6b92ffaSHans Petter Selasky
352*d6b92ffaSHans Petter Selasky if (type == MLX5_ALLOC_TYPE_CONTIG ||
353*d6b92ffaSHans Petter Selasky type == MLX5_ALLOC_TYPE_PREFER_CONTIG ||
354*d6b92ffaSHans Petter Selasky type == MLX5_ALLOC_TYPE_ALL) {
355*d6b92ffaSHans Petter Selasky ret = mlx5_alloc_buf_contig(mctx, buf, size, page_size, component);
356*d6b92ffaSHans Petter Selasky if (!ret)
357*d6b92ffaSHans Petter Selasky return 0;
358*d6b92ffaSHans Petter Selasky
359*d6b92ffaSHans Petter Selasky if (type == MLX5_ALLOC_TYPE_CONTIG)
360*d6b92ffaSHans Petter Selasky return -1;
361*d6b92ffaSHans Petter Selasky mlx5_dbg(stderr, MLX5_DBG_CONTIG,
362*d6b92ffaSHans Petter Selasky "Contig allocation failed, fallback to default mode\n");
363*d6b92ffaSHans Petter Selasky }
364*d6b92ffaSHans Petter Selasky
365*d6b92ffaSHans Petter Selasky return mlx5_alloc_buf(buf, size, page_size);
366*d6b92ffaSHans Petter Selasky
367*d6b92ffaSHans Petter Selasky }
368*d6b92ffaSHans Petter Selasky
mlx5_free_actual_buf(struct mlx5_context * ctx,struct mlx5_buf * buf)369*d6b92ffaSHans Petter Selasky int mlx5_free_actual_buf(struct mlx5_context *ctx, struct mlx5_buf *buf)
370*d6b92ffaSHans Petter Selasky {
371*d6b92ffaSHans Petter Selasky int err = 0;
372*d6b92ffaSHans Petter Selasky
373*d6b92ffaSHans Petter Selasky switch (buf->type) {
374*d6b92ffaSHans Petter Selasky case MLX5_ALLOC_TYPE_ANON:
375*d6b92ffaSHans Petter Selasky mlx5_free_buf(buf);
376*d6b92ffaSHans Petter Selasky break;
377*d6b92ffaSHans Petter Selasky
378*d6b92ffaSHans Petter Selasky case MLX5_ALLOC_TYPE_HUGE:
379*d6b92ffaSHans Petter Selasky free_huge_buf(ctx, buf);
380*d6b92ffaSHans Petter Selasky break;
381*d6b92ffaSHans Petter Selasky
382*d6b92ffaSHans Petter Selasky case MLX5_ALLOC_TYPE_CONTIG:
383*d6b92ffaSHans Petter Selasky mlx5_free_buf_contig(ctx, buf);
384*d6b92ffaSHans Petter Selasky break;
385*d6b92ffaSHans Petter Selasky default:
386*d6b92ffaSHans Petter Selasky fprintf(stderr, "Bad allocation type\n");
387*d6b92ffaSHans Petter Selasky }
388*d6b92ffaSHans Petter Selasky
389*d6b92ffaSHans Petter Selasky return err;
390*d6b92ffaSHans Petter Selasky }
391*d6b92ffaSHans Petter Selasky
392*d6b92ffaSHans Petter Selasky /* This function computes log2(v) rounded up.
393*d6b92ffaSHans Petter Selasky We don't want to have a dependency to libm which exposes ceil & log2 APIs.
394*d6b92ffaSHans Petter Selasky Code was written based on public domain code:
395*d6b92ffaSHans Petter Selasky URL: http://graphics.stanford.edu/~seander/bithacks.html#IntegerLog.
396*d6b92ffaSHans Petter Selasky */
mlx5_get_block_order(uint32_t v)397*d6b92ffaSHans Petter Selasky static uint32_t mlx5_get_block_order(uint32_t v)
398*d6b92ffaSHans Petter Selasky {
399*d6b92ffaSHans Petter Selasky static const uint32_t bits_arr[] = {0x2, 0xC, 0xF0, 0xFF00, 0xFFFF0000};
400*d6b92ffaSHans Petter Selasky static const uint32_t shift_arr[] = {1, 2, 4, 8, 16};
401*d6b92ffaSHans Petter Selasky int i;
402*d6b92ffaSHans Petter Selasky uint32_t input_val = v;
403*d6b92ffaSHans Petter Selasky
404*d6b92ffaSHans Petter Selasky register uint32_t r = 0;/* result of log2(v) will go here */
405*d6b92ffaSHans Petter Selasky for (i = 4; i >= 0; i--) {
406*d6b92ffaSHans Petter Selasky if (v & bits_arr[i]) {
407*d6b92ffaSHans Petter Selasky v >>= shift_arr[i];
408*d6b92ffaSHans Petter Selasky r |= shift_arr[i];
409*d6b92ffaSHans Petter Selasky }
410*d6b92ffaSHans Petter Selasky }
411*d6b92ffaSHans Petter Selasky /* Rounding up if required */
412*d6b92ffaSHans Petter Selasky r += !!(input_val & ((1 << r) - 1));
413*d6b92ffaSHans Petter Selasky
414*d6b92ffaSHans Petter Selasky return r;
415*d6b92ffaSHans Petter Selasky }
416*d6b92ffaSHans Petter Selasky
mlx5_get_alloc_type(const char * component,enum mlx5_alloc_type * alloc_type,enum mlx5_alloc_type default_type)417*d6b92ffaSHans Petter Selasky void mlx5_get_alloc_type(const char *component,
418*d6b92ffaSHans Petter Selasky enum mlx5_alloc_type *alloc_type,
419*d6b92ffaSHans Petter Selasky enum mlx5_alloc_type default_type)
420*d6b92ffaSHans Petter Selasky
421*d6b92ffaSHans Petter Selasky {
422*d6b92ffaSHans Petter Selasky char *env_value;
423*d6b92ffaSHans Petter Selasky char name[128];
424*d6b92ffaSHans Petter Selasky
425*d6b92ffaSHans Petter Selasky snprintf(name, sizeof(name), "%s_ALLOC_TYPE", component);
426*d6b92ffaSHans Petter Selasky
427*d6b92ffaSHans Petter Selasky *alloc_type = default_type;
428*d6b92ffaSHans Petter Selasky
429*d6b92ffaSHans Petter Selasky env_value = getenv(name);
430*d6b92ffaSHans Petter Selasky if (env_value) {
431*d6b92ffaSHans Petter Selasky if (!strcasecmp(env_value, "ANON"))
432*d6b92ffaSHans Petter Selasky *alloc_type = MLX5_ALLOC_TYPE_ANON;
433*d6b92ffaSHans Petter Selasky else if (!strcasecmp(env_value, "HUGE"))
434*d6b92ffaSHans Petter Selasky *alloc_type = MLX5_ALLOC_TYPE_HUGE;
435*d6b92ffaSHans Petter Selasky else if (!strcasecmp(env_value, "CONTIG"))
436*d6b92ffaSHans Petter Selasky *alloc_type = MLX5_ALLOC_TYPE_CONTIG;
437*d6b92ffaSHans Petter Selasky else if (!strcasecmp(env_value, "PREFER_CONTIG"))
438*d6b92ffaSHans Petter Selasky *alloc_type = MLX5_ALLOC_TYPE_PREFER_CONTIG;
439*d6b92ffaSHans Petter Selasky else if (!strcasecmp(env_value, "PREFER_HUGE"))
440*d6b92ffaSHans Petter Selasky *alloc_type = MLX5_ALLOC_TYPE_PREFER_HUGE;
441*d6b92ffaSHans Petter Selasky else if (!strcasecmp(env_value, "ALL"))
442*d6b92ffaSHans Petter Selasky *alloc_type = MLX5_ALLOC_TYPE_ALL;
443*d6b92ffaSHans Petter Selasky }
444*d6b92ffaSHans Petter Selasky }
445*d6b92ffaSHans Petter Selasky
mlx5_alloc_get_env_info(int * max_block_log,int * min_block_log,const char * component)446*d6b92ffaSHans Petter Selasky static void mlx5_alloc_get_env_info(int *max_block_log,
447*d6b92ffaSHans Petter Selasky int *min_block_log,
448*d6b92ffaSHans Petter Selasky const char *component)
449*d6b92ffaSHans Petter Selasky
450*d6b92ffaSHans Petter Selasky {
451*d6b92ffaSHans Petter Selasky char *env;
452*d6b92ffaSHans Petter Selasky int value;
453*d6b92ffaSHans Petter Selasky char name[128];
454*d6b92ffaSHans Petter Selasky
455*d6b92ffaSHans Petter Selasky /* First set defaults */
456*d6b92ffaSHans Petter Selasky *max_block_log = MLX5_MAX_LOG2_CONTIG_BLOCK_SIZE;
457*d6b92ffaSHans Petter Selasky *min_block_log = MLX5_MIN_LOG2_CONTIG_BLOCK_SIZE;
458*d6b92ffaSHans Petter Selasky
459*d6b92ffaSHans Petter Selasky snprintf(name, sizeof(name), "%s_MAX_LOG2_CONTIG_BSIZE", component);
460*d6b92ffaSHans Petter Selasky env = getenv(name);
461*d6b92ffaSHans Petter Selasky if (env) {
462*d6b92ffaSHans Petter Selasky value = atoi(env);
463*d6b92ffaSHans Petter Selasky if (value <= MLX5_MAX_LOG2_CONTIG_BLOCK_SIZE &&
464*d6b92ffaSHans Petter Selasky value >= MLX5_MIN_LOG2_CONTIG_BLOCK_SIZE)
465*d6b92ffaSHans Petter Selasky *max_block_log = value;
466*d6b92ffaSHans Petter Selasky else
467*d6b92ffaSHans Petter Selasky fprintf(stderr, "Invalid value %d for %s\n",
468*d6b92ffaSHans Petter Selasky value, name);
469*d6b92ffaSHans Petter Selasky }
470*d6b92ffaSHans Petter Selasky sprintf(name, "%s_MIN_LOG2_CONTIG_BSIZE", component);
471*d6b92ffaSHans Petter Selasky env = getenv(name);
472*d6b92ffaSHans Petter Selasky if (env) {
473*d6b92ffaSHans Petter Selasky value = atoi(env);
474*d6b92ffaSHans Petter Selasky if (value >= MLX5_MIN_LOG2_CONTIG_BLOCK_SIZE &&
475*d6b92ffaSHans Petter Selasky value <= *max_block_log)
476*d6b92ffaSHans Petter Selasky *min_block_log = value;
477*d6b92ffaSHans Petter Selasky else
478*d6b92ffaSHans Petter Selasky fprintf(stderr, "Invalid value %d for %s\n",
479*d6b92ffaSHans Petter Selasky value, name);
480*d6b92ffaSHans Petter Selasky }
481*d6b92ffaSHans Petter Selasky }
482*d6b92ffaSHans Petter Selasky
mlx5_alloc_buf_contig(struct mlx5_context * mctx,struct mlx5_buf * buf,size_t size,int page_size,const char * component)483*d6b92ffaSHans Petter Selasky int mlx5_alloc_buf_contig(struct mlx5_context *mctx,
484*d6b92ffaSHans Petter Selasky struct mlx5_buf *buf, size_t size,
485*d6b92ffaSHans Petter Selasky int page_size,
486*d6b92ffaSHans Petter Selasky const char *component)
487*d6b92ffaSHans Petter Selasky {
488*d6b92ffaSHans Petter Selasky void *addr = MAP_FAILED;
489*d6b92ffaSHans Petter Selasky int block_size_exp;
490*d6b92ffaSHans Petter Selasky int max_block_log;
491*d6b92ffaSHans Petter Selasky int min_block_log;
492*d6b92ffaSHans Petter Selasky struct ibv_context *context = &mctx->ibv_ctx;
493*d6b92ffaSHans Petter Selasky off_t offset;
494*d6b92ffaSHans Petter Selasky
495*d6b92ffaSHans Petter Selasky mlx5_alloc_get_env_info(&max_block_log,
496*d6b92ffaSHans Petter Selasky &min_block_log,
497*d6b92ffaSHans Petter Selasky component);
498*d6b92ffaSHans Petter Selasky
499*d6b92ffaSHans Petter Selasky block_size_exp = mlx5_get_block_order(size);
500*d6b92ffaSHans Petter Selasky
501*d6b92ffaSHans Petter Selasky if (block_size_exp > max_block_log)
502*d6b92ffaSHans Petter Selasky block_size_exp = max_block_log;
503*d6b92ffaSHans Petter Selasky
504*d6b92ffaSHans Petter Selasky do {
505*d6b92ffaSHans Petter Selasky offset = 0;
506*d6b92ffaSHans Petter Selasky set_command(MLX5_MMAP_GET_CONTIGUOUS_PAGES_CMD, &offset);
507*d6b92ffaSHans Petter Selasky set_order(block_size_exp, &offset);
508*d6b92ffaSHans Petter Selasky addr = mmap(NULL , size, PROT_WRITE | PROT_READ, MAP_SHARED,
509*d6b92ffaSHans Petter Selasky context->cmd_fd, page_size * offset);
510*d6b92ffaSHans Petter Selasky if (addr != MAP_FAILED)
511*d6b92ffaSHans Petter Selasky break;
512*d6b92ffaSHans Petter Selasky
513*d6b92ffaSHans Petter Selasky /*
514*d6b92ffaSHans Petter Selasky * The kernel returns EINVAL if not supported
515*d6b92ffaSHans Petter Selasky */
516*d6b92ffaSHans Petter Selasky if (errno == EINVAL)
517*d6b92ffaSHans Petter Selasky return -1;
518*d6b92ffaSHans Petter Selasky
519*d6b92ffaSHans Petter Selasky block_size_exp -= 1;
520*d6b92ffaSHans Petter Selasky } while (block_size_exp >= min_block_log);
521*d6b92ffaSHans Petter Selasky mlx5_dbg(mctx->dbg_fp, MLX5_DBG_CONTIG, "block order %d, addr %p\n",
522*d6b92ffaSHans Petter Selasky block_size_exp, addr);
523*d6b92ffaSHans Petter Selasky
524*d6b92ffaSHans Petter Selasky if (addr == MAP_FAILED)
525*d6b92ffaSHans Petter Selasky return -1;
526*d6b92ffaSHans Petter Selasky
527*d6b92ffaSHans Petter Selasky if (ibv_dontfork_range(addr, size)) {
528*d6b92ffaSHans Petter Selasky munmap(addr, size);
529*d6b92ffaSHans Petter Selasky return -1;
530*d6b92ffaSHans Petter Selasky }
531*d6b92ffaSHans Petter Selasky
532*d6b92ffaSHans Petter Selasky buf->buf = addr;
533*d6b92ffaSHans Petter Selasky buf->length = size;
534*d6b92ffaSHans Petter Selasky buf->type = MLX5_ALLOC_TYPE_CONTIG;
535*d6b92ffaSHans Petter Selasky
536*d6b92ffaSHans Petter Selasky return 0;
537*d6b92ffaSHans Petter Selasky }
538*d6b92ffaSHans Petter Selasky
mlx5_free_buf_contig(struct mlx5_context * mctx,struct mlx5_buf * buf)539*d6b92ffaSHans Petter Selasky void mlx5_free_buf_contig(struct mlx5_context *mctx, struct mlx5_buf *buf)
540*d6b92ffaSHans Petter Selasky {
541*d6b92ffaSHans Petter Selasky ibv_dofork_range(buf->buf, buf->length);
542*d6b92ffaSHans Petter Selasky munmap(buf->buf, buf->length);
543*d6b92ffaSHans Petter Selasky }
544*d6b92ffaSHans Petter Selasky
mlx5_alloc_buf(struct mlx5_buf * buf,size_t size,int page_size)545*d6b92ffaSHans Petter Selasky int mlx5_alloc_buf(struct mlx5_buf *buf, size_t size, int page_size)
546*d6b92ffaSHans Petter Selasky {
547*d6b92ffaSHans Petter Selasky int ret;
548*d6b92ffaSHans Petter Selasky int al_size;
549*d6b92ffaSHans Petter Selasky
550*d6b92ffaSHans Petter Selasky al_size = align(size, page_size);
551*d6b92ffaSHans Petter Selasky ret = posix_memalign(&buf->buf, page_size, al_size);
552*d6b92ffaSHans Petter Selasky if (ret)
553*d6b92ffaSHans Petter Selasky return ret;
554*d6b92ffaSHans Petter Selasky
555*d6b92ffaSHans Petter Selasky ret = ibv_dontfork_range(buf->buf, al_size);
556*d6b92ffaSHans Petter Selasky if (ret)
557*d6b92ffaSHans Petter Selasky free(buf->buf);
558*d6b92ffaSHans Petter Selasky
559*d6b92ffaSHans Petter Selasky if (!ret) {
560*d6b92ffaSHans Petter Selasky buf->length = al_size;
561*d6b92ffaSHans Petter Selasky buf->type = MLX5_ALLOC_TYPE_ANON;
562*d6b92ffaSHans Petter Selasky }
563*d6b92ffaSHans Petter Selasky
564*d6b92ffaSHans Petter Selasky return ret;
565*d6b92ffaSHans Petter Selasky }
566*d6b92ffaSHans Petter Selasky
mlx5_free_buf(struct mlx5_buf * buf)567*d6b92ffaSHans Petter Selasky void mlx5_free_buf(struct mlx5_buf *buf)
568*d6b92ffaSHans Petter Selasky {
569*d6b92ffaSHans Petter Selasky ibv_dofork_range(buf->buf, buf->length);
570*d6b92ffaSHans Petter Selasky free(buf->buf);
571*d6b92ffaSHans Petter Selasky }
572