Branch data Line data Source code
1 : : /* SPDX-License-Identifier: BSD-3-Clause
2 : : * Copyright 2020 Mellanox Technologies, Ltd
3 : : */
4 : :
5 : : #include <errno.h>
6 : : #include <eal_export.h>
7 : : #include <rte_malloc.h>
8 : : #include <malloc.h>
9 : : #include <stdbool.h>
10 : : #include <string.h>
11 : :
12 : : #include "mlx5_common_log.h"
13 : : #include "mlx5_common_os.h"
14 : : #include "mlx5_malloc.h"
15 : :
16 : : struct mlx5_sys_mem {
17 : : uint32_t init:1; /* Memory allocator initialized. */
18 : : uint32_t enable:1; /* System memory select. */
19 : : uint32_t reserve:30; /* Reserve. */
20 : : RTE_ATOMIC(struct rte_memseg_list *) last_msl;
21 : : /* last allocated rte memory memseg list. */
22 : : #ifdef RTE_LIBRTE_MLX5_DEBUG
23 : : uint64_t malloc_sys;
24 : : /* Memory allocated from system count. */
25 : : uint64_t malloc_rte;
26 : : /* Memory allocated from hugepage count. */
27 : : uint64_t realloc_sys;
28 : : /* Memory reallocate from system count. */
29 : : uint64_t realloc_rte;
30 : : /* Memory reallocate from hugepage count. */
31 : : uint64_t free_sys;
32 : : /* Memory free to system count. */
33 : : uint64_t free_rte;
34 : : /* Memory free to hugepage count. */
35 : : uint64_t msl_miss;
36 : : /* MSL miss count. */
37 : : uint64_t msl_update;
38 : : /* MSL update count. */
39 : : #endif
40 : : };
41 : :
42 : : /* Initialize default as not */
43 : : static struct mlx5_sys_mem mlx5_sys_mem = {
44 : : .init = 0,
45 : : .enable = 0,
46 : : #ifdef RTE_LIBRTE_MLX5_DEBUG
47 : : .malloc_sys = 0,
48 : : .malloc_rte = 0,
49 : : .realloc_sys = 0,
50 : : .realloc_rte = 0,
51 : : .free_sys = 0,
52 : : .free_rte = 0,
53 : : .msl_miss = 0,
54 : : .msl_update = 0,
55 : : #endif
56 : : };
57 : :
58 : : /**
59 : : * Check if the address belongs to memory seg list.
60 : : *
61 : : * @param addr
62 : : * Memory address to be checked.
63 : : * @param msl
64 : : * Memory seg list.
65 : : *
66 : : * @return
67 : : * True if it belongs, false otherwise.
68 : : */
69 : : static bool
70 : : mlx5_mem_check_msl(void *addr, struct rte_memseg_list *msl)
71 : : {
72 : : void *start, *end;
73 : :
74 : 0 : if (!msl)
75 : : return false;
76 : 0 : start = msl->base_va;
77 : 0 : end = RTE_PTR_ADD(start, msl->len);
78 [ # # # # ]: 0 : if (addr >= start && addr < end)
79 : : return true;
80 : : return false;
81 : : }
82 : :
83 : : /**
84 : : * Update the msl if memory belongs to new msl.
85 : : *
86 : : * @param addr
87 : : * Memory address.
88 : : */
89 : : static void
90 : 0 : mlx5_mem_update_msl(void *addr)
91 : : {
92 : : /*
93 : : * Update the cache msl if the new addr comes from the new msl
94 : : * different with the cached msl.
95 : : */
96 [ # # ]: 0 : if (addr && !mlx5_mem_check_msl(addr,
97 [ # # ]: 0 : (struct rte_memseg_list *)rte_atomic_load_explicit
98 : : (&mlx5_sys_mem.last_msl, rte_memory_order_relaxed))) {
99 : 0 : rte_atomic_store_explicit(&mlx5_sys_mem.last_msl,
100 : : rte_mem_virt2memseg_list(addr),
101 : : rte_memory_order_relaxed);
102 : : #ifdef RTE_LIBRTE_MLX5_DEBUG
103 : : rte_atomic_fetch_add_explicit(&mlx5_sys_mem.msl_update, 1,
104 : : rte_memory_order_relaxed);
105 : : #endif
106 : : }
107 : 0 : }
108 : :
109 : : /**
110 : : * Check if the address belongs to rte memory.
111 : : *
112 : : * @param addr
113 : : * Memory address to be checked.
114 : : *
115 : : * @return
116 : : * True if it belongs, false otherwise.
117 : : */
118 : : static bool
119 : 0 : mlx5_mem_is_rte(void *addr)
120 : : {
121 : : /*
122 : : * Check if the last cache msl matches. Drop to slow path
123 : : * to check if the memory belongs to rte memory.
124 : : */
125 : 0 : if (!mlx5_mem_check_msl(addr, (struct rte_memseg_list *)
126 [ # # ]: 0 : rte_atomic_load_explicit(&mlx5_sys_mem.last_msl, rte_memory_order_relaxed))) {
127 [ # # ]: 0 : if (!rte_mem_virt2memseg_list(addr))
128 : 0 : return false;
129 : : #ifdef RTE_LIBRTE_MLX5_DEBUG
130 : : rte_atomic_fetch_add_explicit(&mlx5_sys_mem.msl_miss, 1, rte_memory_order_relaxed);
131 : : #endif
132 : : }
133 : : return true;
134 : : }
135 : :
136 : : /**
137 : : * Allocate memory with alignment.
138 : : *
139 : : * @param size
140 : : * Memory size to be allocated.
141 : : * @param align
142 : : * Memory alignment.
143 : : * @param zero
144 : : * Clear the allocated memory or not.
145 : : *
146 : : * @return
147 : : * Pointer of the allocated memory, NULL otherwise.
148 : : */
149 : : static void *
150 : 0 : mlx5_alloc_align(size_t size, unsigned int align, unsigned int zero)
151 : : {
152 : : void *buf;
153 : :
154 : 0 : buf = mlx5_os_malloc(align, size);
155 [ # # ]: 0 : if (!buf) {
156 : 0 : DRV_LOG(ERR, "Couldn't allocate buf size=%zu align=%u.",
157 : : size, align);
158 : 0 : return NULL;
159 : : }
160 [ # # ]: 0 : if (zero)
161 : : memset(buf, 0, size);
162 : : return buf;
163 : : }
164 : :
165 : : RTE_EXPORT_INTERNAL_SYMBOL(mlx5_malloc)
166 : : void *
167 : 0 : mlx5_malloc(uint32_t flags, size_t size, unsigned int align, int socket)
168 : : {
169 : : void *addr;
170 : : bool rte_mem;
171 : :
172 : : /*
173 : : * If neither system memory nor rte memory is required, allocate
174 : : * memory according to mlx5_sys_mem.enable.
175 : : */
176 [ # # ]: 0 : if (flags & MLX5_MEM_RTE)
177 : : rte_mem = true;
178 [ # # ]: 0 : else if (flags & MLX5_MEM_SYS)
179 : : rte_mem = false;
180 : : else
181 : 0 : rte_mem = mlx5_sys_mem.enable ? false : true;
182 [ # # ]: 0 : if (rte_mem) {
183 [ # # ]: 0 : if (flags & MLX5_MEM_ZERO)
184 : 0 : addr = rte_zmalloc_socket(NULL, size, align, socket);
185 : : else
186 : 0 : addr = rte_malloc_socket(NULL, size, align, socket);
187 : 0 : mlx5_mem_update_msl(addr);
188 : : #ifdef RTE_LIBRTE_MLX5_DEBUG
189 : : if (addr)
190 : : rte_atomic_fetch_add_explicit(&mlx5_sys_mem.malloc_rte, 1,
191 : : rte_memory_order_relaxed);
192 : : #endif
193 : 0 : return addr;
194 : : }
195 : : /* The memory will be allocated from system. */
196 [ # # ]: 0 : if (align > MLX5_MALLOC_ALIGNMENT)
197 : 0 : addr = mlx5_alloc_align(size, align, !!(flags & MLX5_MEM_ZERO));
198 [ # # ]: 0 : else if (flags & MLX5_MEM_ZERO)
199 : 0 : addr = calloc(1, size);
200 : : else
201 : 0 : addr = malloc(size);
202 : : #ifdef RTE_LIBRTE_MLX5_DEBUG
203 : : if (addr)
204 : : rte_atomic_fetch_add_explicit(&mlx5_sys_mem.malloc_sys, 1,
205 : : rte_memory_order_relaxed);
206 : : #endif
207 : : return addr;
208 : : }
209 : :
210 : : RTE_EXPORT_INTERNAL_SYMBOL(mlx5_realloc)
211 : : void *
212 : 0 : mlx5_realloc(void *addr, uint32_t flags, size_t size, unsigned int align,
213 : : int socket)
214 : : {
215 : : void *new_addr;
216 : : bool rte_mem;
217 : :
218 : : /* Allocate directly if old memory address is NULL. */
219 [ # # ]: 0 : if (!addr)
220 : 0 : return mlx5_malloc(flags, size, align, socket);
221 : : /* Get the memory type. */
222 [ # # ]: 0 : if (flags & MLX5_MEM_RTE)
223 : : rte_mem = true;
224 [ # # ]: 0 : else if (flags & MLX5_MEM_SYS)
225 : : rte_mem = false;
226 : : else
227 : 0 : rte_mem = mlx5_sys_mem.enable ? false : true;
228 : : /* Check if old memory and to be allocated memory are the same type. */
229 [ # # ]: 0 : if (rte_mem != mlx5_mem_is_rte(addr)) {
230 : 0 : DRV_LOG(ERR, "Couldn't reallocate to different memory type.");
231 : 0 : return NULL;
232 : : }
233 : : /* Allocate memory from rte memory. */
234 [ # # ]: 0 : if (rte_mem) {
235 : 0 : new_addr = rte_realloc_socket(addr, size, align, socket);
236 : 0 : mlx5_mem_update_msl(new_addr);
237 : : #ifdef RTE_LIBRTE_MLX5_DEBUG
238 : : if (new_addr)
239 : : rte_atomic_fetch_add_explicit(&mlx5_sys_mem.realloc_rte, 1,
240 : : rte_memory_order_relaxed);
241 : : #endif
242 : 0 : return new_addr;
243 : : }
244 : : /* Align is not supported for system memory. */
245 [ # # ]: 0 : if (align) {
246 : 0 : DRV_LOG(ERR, "Couldn't reallocate with alignment");
247 : 0 : return NULL;
248 : : }
249 : 0 : new_addr = realloc(addr, size);
250 : : #ifdef RTE_LIBRTE_MLX5_DEBUG
251 : : if (new_addr)
252 : : rte_atomic_fetch_add_explicit(&mlx5_sys_mem.realloc_sys, 1,
253 : : rte_memory_order_relaxed);
254 : : #endif
255 : 0 : return new_addr;
256 : : }
257 : :
258 : : RTE_EXPORT_INTERNAL_SYMBOL(mlx5_free)
259 : : void
260 : 0 : mlx5_free(void *addr)
261 : : {
262 [ # # ]: 0 : if (addr == NULL)
263 : : return;
264 [ # # ]: 0 : if (!mlx5_mem_is_rte(addr)) {
265 : : #ifdef RTE_LIBRTE_MLX5_DEBUG
266 : : rte_atomic_fetch_add_explicit(&mlx5_sys_mem.free_sys, 1,
267 : : rte_memory_order_relaxed);
268 : : #endif
269 : : mlx5_os_free(addr);
270 : : } else {
271 : : #ifdef RTE_LIBRTE_MLX5_DEBUG
272 : : rte_atomic_fetch_add_explicit(&mlx5_sys_mem.free_rte, 1,
273 : : rte_memory_order_relaxed);
274 : : #endif
275 : 0 : rte_free(addr);
276 : : }
277 : : }
278 : :
279 : : RTE_EXPORT_INTERNAL_SYMBOL(mlx5_memory_stat_dump)
280 : : void
281 : 0 : mlx5_memory_stat_dump(void)
282 : : {
283 : : #ifdef RTE_LIBRTE_MLX5_DEBUG
284 : : DRV_LOG(INFO, "System memory malloc:%"PRIi64", realloc:%"PRIi64","
285 : : " free:%"PRIi64"\nRTE memory malloc:%"PRIi64","
286 : : " realloc:%"PRIi64", free:%"PRIi64"\nMSL miss:%"PRIi64","
287 : : " update:%"PRIi64"",
288 : : rte_atomic_load_explicit(&mlx5_sys_mem.malloc_sys, rte_memory_order_relaxed),
289 : : rte_atomic_load_explicit(&mlx5_sys_mem.realloc_sys, rte_memory_order_relaxed),
290 : : rte_atomic_load_explicit(&mlx5_sys_mem.free_sys, rte_memory_order_relaxed),
291 : : rte_atomic_load_explicit(&mlx5_sys_mem.malloc_rte, rte_memory_order_relaxed),
292 : : rte_atomic_load_explicit(&mlx5_sys_mem.realloc_rte, rte_memory_order_relaxed),
293 : : rte_atomic_load_explicit(&mlx5_sys_mem.free_rte, rte_memory_order_relaxed),
294 : : rte_atomic_load_explicit(&mlx5_sys_mem.msl_miss, rte_memory_order_relaxed),
295 : : rte_atomic_load_explicit(&mlx5_sys_mem.msl_update, rte_memory_order_relaxed));
296 : : #endif
297 : 0 : }
298 : :
299 : : void
300 : 0 : mlx5_malloc_mem_select(uint32_t sys_mem_en)
301 : : {
302 : : /*
303 : : * The initialization should be called only once and all devices
304 : : * should use the same memory type. Otherwise, when new device is
305 : : * being attached with some different memory allocation configuration,
306 : : * the memory will get wrong behavior or a failure will be raised.
307 : : */
308 [ # # ]: 0 : if (!mlx5_sys_mem.init) {
309 [ # # ]: 0 : if (sys_mem_en)
310 : 0 : mlx5_sys_mem.enable = 1;
311 : 0 : mlx5_sys_mem.init = 1;
312 [ # # ]: 0 : DRV_LOG(INFO, "%s is selected.", sys_mem_en ? "SYS_MEM" : "RTE_MEM");
313 [ # # ]: 0 : } else if (mlx5_sys_mem.enable != sys_mem_en) {
314 [ # # ]: 0 : DRV_LOG(WARNING, "%s is already selected.",
315 : : mlx5_sys_mem.enable ? "SYS_MEM" : "RTE_MEM");
316 : : }
317 : 0 : }
|