Commit | Line | Data |
---|---|---|
e126ba97 | 1 | /* |
302bdf68 | 2 | * Copyright (c) 2013-2015, Mellanox Technologies. All rights reserved. |
e126ba97 EC |
3 | * |
4 | * This software is available to you under a choice of one of two | |
5 | * licenses. You may choose to be licensed under the terms of the GNU | |
6 | * General Public License (GPL) Version 2, available from the file | |
7 | * COPYING in the main directory of this source tree, or the | |
8 | * OpenIB.org BSD license below: | |
9 | * | |
10 | * Redistribution and use in source and binary forms, with or | |
11 | * without modification, are permitted provided that the following | |
12 | * conditions are met: | |
13 | * | |
14 | * - Redistributions of source code must retain the above | |
15 | * copyright notice, this list of conditions and the following | |
16 | * disclaimer. | |
17 | * | |
18 | * - Redistributions in binary form must reproduce the above | |
19 | * copyright notice, this list of conditions and the following | |
20 | * disclaimer in the documentation and/or other materials | |
21 | * provided with the distribution. | |
22 | * | |
23 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | |
24 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | |
25 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | |
26 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS | |
27 | * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN | |
28 | * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN | |
29 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | |
30 | * SOFTWARE. | |
31 | */ | |
32 | ||
33 | #include <asm-generic/kmap_types.h> | |
34 | #include <linux/kernel.h> | |
35 | #include <linux/module.h> | |
36 | #include <linux/mlx5/driver.h> | |
37 | #include <linux/mlx5/cmd.h> | |
38 | #include "mlx5_core.h" | |
39 | ||
40 | enum { | |
41 | MLX5_PAGES_CANT_GIVE = 0, | |
42 | MLX5_PAGES_GIVE = 1, | |
43 | MLX5_PAGES_TAKE = 2 | |
44 | }; | |
45 | ||
0a324f31 ML |
46 | enum { |
47 | MLX5_BOOT_PAGES = 1, | |
48 | MLX5_INIT_PAGES = 2, | |
49 | MLX5_POST_INIT_PAGES = 3 | |
50 | }; | |
51 | ||
e126ba97 EC |
52 | struct mlx5_pages_req { |
53 | struct mlx5_core_dev *dev; | |
f241e749 | 54 | u16 func_id; |
0a324f31 | 55 | s32 npages; |
e126ba97 EC |
56 | struct work_struct work; |
57 | }; | |
58 | ||
59 | struct fw_page { | |
bf0bf77f EC |
60 | struct rb_node rb_node; |
61 | u64 addr; | |
62 | struct page *page; | |
63 | u16 func_id; | |
64 | unsigned long bitmask; | |
65 | struct list_head list; | |
66 | unsigned free_count; | |
e126ba97 EC |
67 | }; |
68 | ||
69 | struct mlx5_query_pages_inbox { | |
70 | struct mlx5_inbox_hdr hdr; | |
71 | u8 rsvd[8]; | |
72 | }; | |
73 | ||
74 | struct mlx5_query_pages_outbox { | |
75 | struct mlx5_outbox_hdr hdr; | |
0a324f31 | 76 | __be16 rsvd; |
e126ba97 | 77 | __be16 func_id; |
0a324f31 | 78 | __be32 num_pages; |
e126ba97 EC |
79 | }; |
80 | ||
81 | struct mlx5_manage_pages_inbox { | |
82 | struct mlx5_inbox_hdr hdr; | |
0a324f31 | 83 | __be16 rsvd; |
e126ba97 | 84 | __be16 func_id; |
0a324f31 | 85 | __be32 num_entries; |
e126ba97 EC |
86 | __be64 pas[0]; |
87 | }; | |
88 | ||
89 | struct mlx5_manage_pages_outbox { | |
90 | struct mlx5_outbox_hdr hdr; | |
0a324f31 ML |
91 | __be32 num_entries; |
92 | u8 rsvd[4]; | |
e126ba97 EC |
93 | __be64 pas[0]; |
94 | }; | |
95 | ||
dabed0e6 EC |
96 | enum { |
97 | MAX_RECLAIM_TIME_MSECS = 5000, | |
98 | }; | |
99 | ||
bf0bf77f EC |
100 | enum { |
101 | MLX5_MAX_RECLAIM_TIME_MILI = 5000, | |
05bdb2ab | 102 | MLX5_NUM_4K_IN_PAGE = PAGE_SIZE / MLX5_ADAPTER_PAGE_SIZE, |
bf0bf77f EC |
103 | }; |
104 | ||
e126ba97 EC |
105 | static int insert_page(struct mlx5_core_dev *dev, u64 addr, struct page *page, u16 func_id) |
106 | { | |
107 | struct rb_root *root = &dev->priv.page_root; | |
108 | struct rb_node **new = &root->rb_node; | |
109 | struct rb_node *parent = NULL; | |
110 | struct fw_page *nfp; | |
111 | struct fw_page *tfp; | |
bf0bf77f | 112 | int i; |
e126ba97 EC |
113 | |
114 | while (*new) { | |
115 | parent = *new; | |
116 | tfp = rb_entry(parent, struct fw_page, rb_node); | |
117 | if (tfp->addr < addr) | |
118 | new = &parent->rb_left; | |
119 | else if (tfp->addr > addr) | |
120 | new = &parent->rb_right; | |
121 | else | |
122 | return -EEXIST; | |
123 | } | |
124 | ||
bf0bf77f | 125 | nfp = kzalloc(sizeof(*nfp), GFP_KERNEL); |
e126ba97 EC |
126 | if (!nfp) |
127 | return -ENOMEM; | |
128 | ||
129 | nfp->addr = addr; | |
130 | nfp->page = page; | |
131 | nfp->func_id = func_id; | |
bf0bf77f EC |
132 | nfp->free_count = MLX5_NUM_4K_IN_PAGE; |
133 | for (i = 0; i < MLX5_NUM_4K_IN_PAGE; i++) | |
134 | set_bit(i, &nfp->bitmask); | |
e126ba97 EC |
135 | |
136 | rb_link_node(&nfp->rb_node, parent, new); | |
137 | rb_insert_color(&nfp->rb_node, root); | |
bf0bf77f | 138 | list_add(&nfp->list, &dev->priv.free_list); |
e126ba97 EC |
139 | |
140 | return 0; | |
141 | } | |
142 | ||
bf0bf77f | 143 | static struct fw_page *find_fw_page(struct mlx5_core_dev *dev, u64 addr) |
e126ba97 EC |
144 | { |
145 | struct rb_root *root = &dev->priv.page_root; | |
146 | struct rb_node *tmp = root->rb_node; | |
bf0bf77f | 147 | struct fw_page *result = NULL; |
e126ba97 EC |
148 | struct fw_page *tfp; |
149 | ||
150 | while (tmp) { | |
151 | tfp = rb_entry(tmp, struct fw_page, rb_node); | |
152 | if (tfp->addr < addr) { | |
153 | tmp = tmp->rb_left; | |
154 | } else if (tfp->addr > addr) { | |
155 | tmp = tmp->rb_right; | |
156 | } else { | |
bf0bf77f | 157 | result = tfp; |
e126ba97 EC |
158 | break; |
159 | } | |
160 | } | |
161 | ||
162 | return result; | |
163 | } | |
164 | ||
165 | static int mlx5_cmd_query_pages(struct mlx5_core_dev *dev, u16 *func_id, | |
0a324f31 | 166 | s32 *npages, int boot) |
e126ba97 EC |
167 | { |
168 | struct mlx5_query_pages_inbox in; | |
169 | struct mlx5_query_pages_outbox out; | |
170 | int err; | |
171 | ||
172 | memset(&in, 0, sizeof(in)); | |
173 | memset(&out, 0, sizeof(out)); | |
174 | in.hdr.opcode = cpu_to_be16(MLX5_CMD_OP_QUERY_PAGES); | |
0a324f31 ML |
175 | in.hdr.opmod = boot ? cpu_to_be16(MLX5_BOOT_PAGES) : cpu_to_be16(MLX5_INIT_PAGES); |
176 | ||
e126ba97 EC |
177 | err = mlx5_cmd_exec(dev, &in, sizeof(in), &out, sizeof(out)); |
178 | if (err) | |
179 | return err; | |
180 | ||
181 | if (out.hdr.status) | |
182 | return mlx5_cmd_status_to_err(&out.hdr); | |
183 | ||
0a324f31 | 184 | *npages = be32_to_cpu(out.num_pages); |
e126ba97 EC |
185 | *func_id = be16_to_cpu(out.func_id); |
186 | ||
187 | return err; | |
188 | } | |
189 | ||
bf0bf77f EC |
190 | static int alloc_4k(struct mlx5_core_dev *dev, u64 *addr) |
191 | { | |
192 | struct fw_page *fp; | |
193 | unsigned n; | |
194 | ||
24e42754 | 195 | if (list_empty(&dev->priv.free_list)) |
bf0bf77f | 196 | return -ENOMEM; |
bf0bf77f EC |
197 | |
198 | fp = list_entry(dev->priv.free_list.next, struct fw_page, list); | |
199 | n = find_first_bit(&fp->bitmask, 8 * sizeof(fp->bitmask)); | |
200 | if (n >= MLX5_NUM_4K_IN_PAGE) { | |
201 | mlx5_core_warn(dev, "alloc 4k bug\n"); | |
202 | return -ENOENT; | |
203 | } | |
204 | clear_bit(n, &fp->bitmask); | |
205 | fp->free_count--; | |
206 | if (!fp->free_count) | |
207 | list_del(&fp->list); | |
208 | ||
05bdb2ab | 209 | *addr = fp->addr + n * MLX5_ADAPTER_PAGE_SIZE; |
bf0bf77f EC |
210 | |
211 | return 0; | |
212 | } | |
213 | ||
59d2d18c HL |
214 | #define MLX5_U64_4K_PAGE_MASK ((~(u64)0U) << PAGE_SHIFT) |
215 | ||
bf0bf77f EC |
216 | static void free_4k(struct mlx5_core_dev *dev, u64 addr) |
217 | { | |
218 | struct fw_page *fwp; | |
219 | int n; | |
220 | ||
59d2d18c | 221 | fwp = find_fw_page(dev, addr & MLX5_U64_4K_PAGE_MASK); |
bf0bf77f EC |
222 | if (!fwp) { |
223 | mlx5_core_warn(dev, "page not found\n"); | |
224 | return; | |
225 | } | |
226 | ||
59d2d18c | 227 | n = (addr & ~MLX5_U64_4K_PAGE_MASK) >> MLX5_ADAPTER_PAGE_SHIFT; |
bf0bf77f EC |
228 | fwp->free_count++; |
229 | set_bit(n, &fwp->bitmask); | |
230 | if (fwp->free_count == MLX5_NUM_4K_IN_PAGE) { | |
231 | rb_erase(&fwp->rb_node, &dev->priv.page_root); | |
2b136d02 EC |
232 | if (fwp->free_count != 1) |
233 | list_del(&fwp->list); | |
59d2d18c HL |
234 | dma_unmap_page(&dev->pdev->dev, addr & MLX5_U64_4K_PAGE_MASK, |
235 | PAGE_SIZE, DMA_BIDIRECTIONAL); | |
bf0bf77f EC |
236 | __free_page(fwp->page); |
237 | kfree(fwp); | |
238 | } else if (fwp->free_count == 1) { | |
239 | list_add(&fwp->list, &dev->priv.free_list); | |
240 | } | |
241 | } | |
242 | ||
243 | static int alloc_system_page(struct mlx5_core_dev *dev, u16 func_id) | |
244 | { | |
245 | struct page *page; | |
246 | u64 addr; | |
247 | int err; | |
ad189106 | 248 | int nid = dev_to_node(&dev->pdev->dev); |
bf0bf77f | 249 | |
ad189106 | 250 | page = alloc_pages_node(nid, GFP_HIGHUSER, 0); |
bf0bf77f EC |
251 | if (!page) { |
252 | mlx5_core_warn(dev, "failed to allocate page\n"); | |
253 | return -ENOMEM; | |
254 | } | |
255 | addr = dma_map_page(&dev->pdev->dev, page, 0, | |
256 | PAGE_SIZE, DMA_BIDIRECTIONAL); | |
257 | if (dma_mapping_error(&dev->pdev->dev, addr)) { | |
258 | mlx5_core_warn(dev, "failed dma mapping page\n"); | |
259 | err = -ENOMEM; | |
260 | goto out_alloc; | |
261 | } | |
262 | err = insert_page(dev, addr, page, func_id); | |
263 | if (err) { | |
264 | mlx5_core_err(dev, "failed to track allocated page\n"); | |
265 | goto out_mapping; | |
266 | } | |
267 | ||
268 | return 0; | |
269 | ||
270 | out_mapping: | |
271 | dma_unmap_page(&dev->pdev->dev, addr, PAGE_SIZE, DMA_BIDIRECTIONAL); | |
272 | ||
273 | out_alloc: | |
274 | __free_page(page); | |
275 | ||
276 | return err; | |
277 | } | |
e126ba97 EC |
278 | static int give_pages(struct mlx5_core_dev *dev, u16 func_id, int npages, |
279 | int notify_fail) | |
280 | { | |
281 | struct mlx5_manage_pages_inbox *in; | |
282 | struct mlx5_manage_pages_outbox out; | |
952f5f6e | 283 | struct mlx5_manage_pages_inbox *nin; |
e126ba97 EC |
284 | int inlen; |
285 | u64 addr; | |
286 | int err; | |
287 | int i; | |
288 | ||
289 | inlen = sizeof(*in) + npages * sizeof(in->pas[0]); | |
290 | in = mlx5_vzalloc(inlen); | |
291 | if (!in) { | |
292 | mlx5_core_warn(dev, "vzalloc failed %d\n", inlen); | |
293 | return -ENOMEM; | |
294 | } | |
295 | memset(&out, 0, sizeof(out)); | |
296 | ||
297 | for (i = 0; i < npages; i++) { | |
bf0bf77f EC |
298 | retry: |
299 | err = alloc_4k(dev, &addr); | |
e126ba97 | 300 | if (err) { |
bf0bf77f EC |
301 | if (err == -ENOMEM) |
302 | err = alloc_system_page(dev, func_id); | |
303 | if (err) | |
304 | goto out_4k; | |
305 | ||
306 | goto retry; | |
e126ba97 EC |
307 | } |
308 | in->pas[i] = cpu_to_be64(addr); | |
309 | } | |
310 | ||
311 | in->hdr.opcode = cpu_to_be16(MLX5_CMD_OP_MANAGE_PAGES); | |
312 | in->hdr.opmod = cpu_to_be16(MLX5_PAGES_GIVE); | |
313 | in->func_id = cpu_to_be16(func_id); | |
0a324f31 | 314 | in->num_entries = cpu_to_be32(npages); |
e126ba97 | 315 | err = mlx5_cmd_exec(dev, in, inlen, &out, sizeof(out)); |
e126ba97 | 316 | if (err) { |
1a91de28 JP |
317 | mlx5_core_warn(dev, "func_id 0x%x, npages %d, err %d\n", |
318 | func_id, npages, err); | |
e126ba97 EC |
319 | goto out_alloc; |
320 | } | |
321 | dev->priv.fw_pages += npages; | |
322 | ||
323 | if (out.hdr.status) { | |
324 | err = mlx5_cmd_status_to_err(&out.hdr); | |
325 | if (err) { | |
1a91de28 JP |
326 | mlx5_core_warn(dev, "func_id 0x%x, npages %d, status %d\n", |
327 | func_id, npages, out.hdr.status); | |
e126ba97 EC |
328 | goto out_alloc; |
329 | } | |
330 | } | |
331 | ||
332 | mlx5_core_dbg(dev, "err %d\n", err); | |
333 | ||
334 | goto out_free; | |
335 | ||
336 | out_alloc: | |
337 | if (notify_fail) { | |
952f5f6e EC |
338 | nin = kzalloc(sizeof(*nin), GFP_KERNEL); |
339 | if (!nin) { | |
340 | mlx5_core_warn(dev, "allocation failed\n"); | |
bf0bf77f | 341 | goto out_4k; |
952f5f6e | 342 | } |
e126ba97 | 343 | memset(&out, 0, sizeof(out)); |
952f5f6e EC |
344 | nin->hdr.opcode = cpu_to_be16(MLX5_CMD_OP_MANAGE_PAGES); |
345 | nin->hdr.opmod = cpu_to_be16(MLX5_PAGES_CANT_GIVE); | |
346 | if (mlx5_cmd_exec(dev, nin, sizeof(*nin), &out, sizeof(out))) | |
347 | mlx5_core_warn(dev, "page notify failed\n"); | |
348 | kfree(nin); | |
e126ba97 | 349 | } |
952f5f6e | 350 | |
bf0bf77f EC |
351 | out_4k: |
352 | for (i--; i >= 0; i--) | |
353 | free_4k(dev, be64_to_cpu(in->pas[i])); | |
e126ba97 | 354 | out_free: |
479163f4 | 355 | kvfree(in); |
e126ba97 EC |
356 | return err; |
357 | } | |
358 | ||
359 | static int reclaim_pages(struct mlx5_core_dev *dev, u32 func_id, int npages, | |
360 | int *nclaimed) | |
361 | { | |
362 | struct mlx5_manage_pages_inbox in; | |
363 | struct mlx5_manage_pages_outbox *out; | |
e126ba97 EC |
364 | int num_claimed; |
365 | int outlen; | |
366 | u64 addr; | |
367 | int err; | |
368 | int i; | |
369 | ||
dabed0e6 EC |
370 | if (nclaimed) |
371 | *nclaimed = 0; | |
372 | ||
e126ba97 EC |
373 | memset(&in, 0, sizeof(in)); |
374 | outlen = sizeof(*out) + npages * sizeof(out->pas[0]); | |
375 | out = mlx5_vzalloc(outlen); | |
376 | if (!out) | |
377 | return -ENOMEM; | |
378 | ||
379 | in.hdr.opcode = cpu_to_be16(MLX5_CMD_OP_MANAGE_PAGES); | |
380 | in.hdr.opmod = cpu_to_be16(MLX5_PAGES_TAKE); | |
381 | in.func_id = cpu_to_be16(func_id); | |
0a324f31 | 382 | in.num_entries = cpu_to_be32(npages); |
e126ba97 EC |
383 | mlx5_core_dbg(dev, "npages %d, outlen %d\n", npages, outlen); |
384 | err = mlx5_cmd_exec(dev, &in, sizeof(in), out, outlen); | |
385 | if (err) { | |
1a91de28 | 386 | mlx5_core_err(dev, "failed reclaiming pages\n"); |
e126ba97 EC |
387 | goto out_free; |
388 | } | |
389 | dev->priv.fw_pages -= npages; | |
390 | ||
391 | if (out->hdr.status) { | |
392 | err = mlx5_cmd_status_to_err(&out->hdr); | |
393 | goto out_free; | |
394 | } | |
395 | ||
0a324f31 | 396 | num_claimed = be32_to_cpu(out->num_entries); |
e126ba97 EC |
397 | if (nclaimed) |
398 | *nclaimed = num_claimed; | |
399 | ||
400 | for (i = 0; i < num_claimed; i++) { | |
401 | addr = be64_to_cpu(out->pas[i]); | |
bf0bf77f | 402 | free_4k(dev, addr); |
e126ba97 EC |
403 | } |
404 | ||
405 | out_free: | |
479163f4 | 406 | kvfree(out); |
e126ba97 EC |
407 | return err; |
408 | } | |
409 | ||
410 | static void pages_work_handler(struct work_struct *work) | |
411 | { | |
412 | struct mlx5_pages_req *req = container_of(work, struct mlx5_pages_req, work); | |
413 | struct mlx5_core_dev *dev = req->dev; | |
414 | int err = 0; | |
415 | ||
416 | if (req->npages < 0) | |
417 | err = reclaim_pages(dev, req->func_id, -1 * req->npages, NULL); | |
418 | else if (req->npages > 0) | |
419 | err = give_pages(dev, req->func_id, req->npages, 1); | |
420 | ||
421 | if (err) | |
1a91de28 JP |
422 | mlx5_core_warn(dev, "%s fail %d\n", |
423 | req->npages < 0 ? "reclaim" : "give", err); | |
e126ba97 EC |
424 | |
425 | kfree(req); | |
426 | } | |
427 | ||
428 | void mlx5_core_req_pages_handler(struct mlx5_core_dev *dev, u16 func_id, | |
0a324f31 | 429 | s32 npages) |
e126ba97 EC |
430 | { |
431 | struct mlx5_pages_req *req; | |
432 | ||
433 | req = kzalloc(sizeof(*req), GFP_ATOMIC); | |
434 | if (!req) { | |
435 | mlx5_core_warn(dev, "failed to allocate pages request\n"); | |
436 | return; | |
437 | } | |
438 | ||
439 | req->dev = dev; | |
440 | req->func_id = func_id; | |
441 | req->npages = npages; | |
442 | INIT_WORK(&req->work, pages_work_handler); | |
443 | queue_work(dev->priv.pg_wq, &req->work); | |
444 | } | |
445 | ||
cd23b14b | 446 | int mlx5_satisfy_startup_pages(struct mlx5_core_dev *dev, int boot) |
e126ba97 | 447 | { |
e126ba97 | 448 | u16 uninitialized_var(func_id); |
0a324f31 | 449 | s32 uninitialized_var(npages); |
e126ba97 EC |
450 | int err; |
451 | ||
0a324f31 | 452 | err = mlx5_cmd_query_pages(dev, &func_id, &npages, boot); |
e126ba97 EC |
453 | if (err) |
454 | return err; | |
455 | ||
0a324f31 ML |
456 | mlx5_core_dbg(dev, "requested %d %s pages for func_id 0x%x\n", |
457 | npages, boot ? "boot" : "init", func_id); | |
e126ba97 | 458 | |
0a324f31 | 459 | return give_pages(dev, func_id, npages, 0); |
e126ba97 EC |
460 | } |
461 | ||
4e3d677b ML |
462 | enum { |
463 | MLX5_BLKS_FOR_RECLAIM_PAGES = 12 | |
464 | }; | |
465 | ||
e126ba97 EC |
466 | static int optimal_reclaimed_pages(void) |
467 | { | |
468 | struct mlx5_cmd_prot_block *block; | |
469 | struct mlx5_cmd_layout *lay; | |
470 | int ret; | |
471 | ||
4e3d677b ML |
472 | ret = (sizeof(lay->out) + MLX5_BLKS_FOR_RECLAIM_PAGES * sizeof(block->data) - |
473 | sizeof(struct mlx5_manage_pages_outbox)) / | |
474 | FIELD_SIZEOF(struct mlx5_manage_pages_outbox, pas[0]); | |
e126ba97 EC |
475 | |
476 | return ret; | |
477 | } | |
478 | ||
479 | int mlx5_reclaim_startup_pages(struct mlx5_core_dev *dev) | |
480 | { | |
dabed0e6 | 481 | unsigned long end = jiffies + msecs_to_jiffies(MAX_RECLAIM_TIME_MSECS); |
e126ba97 EC |
482 | struct fw_page *fwp; |
483 | struct rb_node *p; | |
dabed0e6 | 484 | int nclaimed = 0; |
e126ba97 EC |
485 | int err; |
486 | ||
487 | do { | |
488 | p = rb_first(&dev->priv.page_root); | |
489 | if (p) { | |
490 | fwp = rb_entry(p, struct fw_page, rb_node); | |
dabed0e6 EC |
491 | err = reclaim_pages(dev, fwp->func_id, |
492 | optimal_reclaimed_pages(), | |
493 | &nclaimed); | |
e126ba97 | 494 | if (err) { |
1a91de28 JP |
495 | mlx5_core_warn(dev, "failed reclaiming pages (%d)\n", |
496 | err); | |
e126ba97 EC |
497 | return err; |
498 | } | |
dabed0e6 EC |
499 | if (nclaimed) |
500 | end = jiffies + msecs_to_jiffies(MAX_RECLAIM_TIME_MSECS); | |
e126ba97 EC |
501 | } |
502 | if (time_after(jiffies, end)) { | |
503 | mlx5_core_warn(dev, "FW did not return all pages. giving up...\n"); | |
504 | break; | |
505 | } | |
506 | } while (p); | |
507 | ||
508 | return 0; | |
509 | } | |
510 | ||
511 | void mlx5_pagealloc_init(struct mlx5_core_dev *dev) | |
512 | { | |
513 | dev->priv.page_root = RB_ROOT; | |
bf0bf77f | 514 | INIT_LIST_HEAD(&dev->priv.free_list); |
e126ba97 EC |
515 | } |
516 | ||
517 | void mlx5_pagealloc_cleanup(struct mlx5_core_dev *dev) | |
518 | { | |
519 | /* nothing */ | |
520 | } | |
521 | ||
522 | int mlx5_pagealloc_start(struct mlx5_core_dev *dev) | |
523 | { | |
524 | dev->priv.pg_wq = create_singlethread_workqueue("mlx5_page_allocator"); | |
525 | if (!dev->priv.pg_wq) | |
526 | return -ENOMEM; | |
527 | ||
528 | return 0; | |
529 | } | |
530 | ||
531 | void mlx5_pagealloc_stop(struct mlx5_core_dev *dev) | |
532 | { | |
533 | destroy_workqueue(dev->priv.pg_wq); | |
534 | } |