xref: /freebsd/contrib/ofed/libmlx5/buf.c (revision 87181516ef48be852d5e5fee53c6e0dbfc62f21e)
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