1 /*
2  * Copyright (c) 2013-2015, Mellanox Technologies. All rights reserved.
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 
46 enum {
47 	MLX5_BOOT_PAGES		= 1,
48 	MLX5_INIT_PAGES		= 2,
49 	MLX5_POST_INIT_PAGES	= 3
50 };
51 
52 struct mlx5_pages_req {
53 	struct mlx5_core_dev *dev;
54 	u16	func_id;
55 	s32	npages;
56 	struct work_struct work;
57 };
58 
59 struct fw_page {
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;
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;
76 	__be16			rsvd;
77 	__be16			func_id;
78 	__be32			num_pages;
79 };
80 
81 struct mlx5_manage_pages_inbox {
82 	struct mlx5_inbox_hdr	hdr;
83 	__be16			rsvd;
84 	__be16			func_id;
85 	__be32			num_entries;
86 	__be64			pas[0];
87 };
88 
89 struct mlx5_manage_pages_outbox {
90 	struct mlx5_outbox_hdr	hdr;
91 	__be32			num_entries;
92 	u8			rsvd[4];
93 	__be64			pas[0];
94 };
95 
96 enum {
97 	MAX_RECLAIM_TIME_MSECS	= 5000,
98 };
99 
100 enum {
101 	MLX5_MAX_RECLAIM_TIME_MILI	= 5000,
102 	MLX5_NUM_4K_IN_PAGE		= PAGE_SIZE / MLX5_ADAPTER_PAGE_SIZE,
103 };
104 
insert_page(struct mlx5_core_dev * dev,u64 addr,struct page * page,u16 func_id)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;
112 	int i;
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 
125 	nfp = kzalloc(sizeof(*nfp), GFP_KERNEL);
126 	if (!nfp)
127 		return -ENOMEM;
128 
129 	nfp->addr = addr;
130 	nfp->page = page;
131 	nfp->func_id = func_id;
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);
135 
136 	rb_link_node(&nfp->rb_node, parent, new);
137 	rb_insert_color(&nfp->rb_node, root);
138 	list_add(&nfp->list, &dev->priv.free_list);
139 
140 	return 0;
141 }
142 
find_fw_page(struct mlx5_core_dev * dev,u64 addr)143 static struct fw_page *find_fw_page(struct mlx5_core_dev *dev, u64 addr)
144 {
145 	struct rb_root *root = &dev->priv.page_root;
146 	struct rb_node *tmp = root->rb_node;
147 	struct fw_page *result = NULL;
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 {
157 			result = tfp;
158 			break;
159 		}
160 	}
161 
162 	return result;
163 }
164 
mlx5_cmd_query_pages(struct mlx5_core_dev * dev,u16 * func_id,s32 * npages,int boot)165 static int mlx5_cmd_query_pages(struct mlx5_core_dev *dev, u16 *func_id,
166 				s32 *npages, int boot)
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);
175 	in.hdr.opmod = boot ? cpu_to_be16(MLX5_BOOT_PAGES) : cpu_to_be16(MLX5_INIT_PAGES);
176 
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 
184 	*npages = be32_to_cpu(out.num_pages);
185 	*func_id = be16_to_cpu(out.func_id);
186 
187 	return err;
188 }
189 
alloc_4k(struct mlx5_core_dev * dev,u64 * addr)190 static int alloc_4k(struct mlx5_core_dev *dev, u64 *addr)
191 {
192 	struct fw_page *fp;
193 	unsigned n;
194 
195 	if (list_empty(&dev->priv.free_list))
196 		return -ENOMEM;
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 
209 	*addr = fp->addr + n * MLX5_ADAPTER_PAGE_SIZE;
210 
211 	return 0;
212 }
213 
214 #define MLX5_U64_4K_PAGE_MASK ((~(u64)0U) << PAGE_SHIFT)
215 
free_4k(struct mlx5_core_dev * dev,u64 addr)216 static void free_4k(struct mlx5_core_dev *dev, u64 addr)
217 {
218 	struct fw_page *fwp;
219 	int n;
220 
221 	fwp = find_fw_page(dev, addr & MLX5_U64_4K_PAGE_MASK);
222 	if (!fwp) {
223 		mlx5_core_warn(dev, "page not found\n");
224 		return;
225 	}
226 
227 	n = (addr & ~MLX5_U64_4K_PAGE_MASK) >> MLX5_ADAPTER_PAGE_SHIFT;
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);
232 		if (fwp->free_count != 1)
233 			list_del(&fwp->list);
234 		dma_unmap_page(&dev->pdev->dev, addr & MLX5_U64_4K_PAGE_MASK,
235 			       PAGE_SIZE, DMA_BIDIRECTIONAL);
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 
alloc_system_page(struct mlx5_core_dev * dev,u16 func_id)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;
248 	int nid = dev_to_node(&dev->pdev->dev);
249 
250 	page = alloc_pages_node(nid, GFP_HIGHUSER, 0);
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 }
give_pages(struct mlx5_core_dev * dev,u16 func_id,int npages,int notify_fail)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;
283 	struct mlx5_manage_pages_inbox *nin;
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++) {
298 retry:
299 		err = alloc_4k(dev, &addr);
300 		if (err) {
301 			if (err == -ENOMEM)
302 				err = alloc_system_page(dev, func_id);
303 			if (err)
304 				goto out_4k;
305 
306 			goto retry;
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);
314 	in->num_entries = cpu_to_be32(npages);
315 	err = mlx5_cmd_exec(dev, in, inlen, &out, sizeof(out));
316 	if (err) {
317 		mlx5_core_warn(dev, "func_id 0x%x, npages %d, err %d\n",
318 			       func_id, npages, err);
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) {
326 			mlx5_core_warn(dev, "func_id 0x%x, npages %d, status %d\n",
327 				       func_id, npages, out.hdr.status);
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) {
338 		nin = kzalloc(sizeof(*nin), GFP_KERNEL);
339 		if (!nin) {
340 			mlx5_core_warn(dev, "allocation failed\n");
341 			goto out_4k;
342 		}
343 		memset(&out, 0, sizeof(out));
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);
349 	}
350 
351 out_4k:
352 	for (i--; i >= 0; i--)
353 		free_4k(dev, be64_to_cpu(in->pas[i]));
354 out_free:
355 	kvfree(in);
356 	return err;
357 }
358 
reclaim_pages(struct mlx5_core_dev * dev,u32 func_id,int npages,int * nclaimed)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;
364 	int num_claimed;
365 	int outlen;
366 	u64 addr;
367 	int err;
368 	int i;
369 
370 	if (nclaimed)
371 		*nclaimed = 0;
372 
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);
382 	in.num_entries = cpu_to_be32(npages);
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) {
386 		mlx5_core_err(dev, "failed reclaiming pages\n");
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 
396 	num_claimed = be32_to_cpu(out->num_entries);
397 	if (nclaimed)
398 		*nclaimed = num_claimed;
399 
400 	for (i = 0; i < num_claimed; i++) {
401 		addr = be64_to_cpu(out->pas[i]);
402 		free_4k(dev, addr);
403 	}
404 
405 out_free:
406 	kvfree(out);
407 	return err;
408 }
409 
pages_work_handler(struct work_struct * work)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)
422 		mlx5_core_warn(dev, "%s fail %d\n",
423 			       req->npages < 0 ? "reclaim" : "give", err);
424 
425 	kfree(req);
426 }
427 
mlx5_core_req_pages_handler(struct mlx5_core_dev * dev,u16 func_id,s32 npages)428 void mlx5_core_req_pages_handler(struct mlx5_core_dev *dev, u16 func_id,
429 				 s32 npages)
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 
mlx5_satisfy_startup_pages(struct mlx5_core_dev * dev,int boot)446 int mlx5_satisfy_startup_pages(struct mlx5_core_dev *dev, int boot)
447 {
448 	u16 uninitialized_var(func_id);
449 	s32 uninitialized_var(npages);
450 	int err;
451 
452 	err = mlx5_cmd_query_pages(dev, &func_id, &npages, boot);
453 	if (err)
454 		return err;
455 
456 	mlx5_core_dbg(dev, "requested %d %s pages for func_id 0x%x\n",
457 		      npages, boot ? "boot" : "init", func_id);
458 
459 	return give_pages(dev, func_id, npages, 0);
460 }
461 
462 enum {
463 	MLX5_BLKS_FOR_RECLAIM_PAGES = 12
464 };
465 
optimal_reclaimed_pages(void)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 
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]);
475 
476 	return ret;
477 }
478 
mlx5_reclaim_startup_pages(struct mlx5_core_dev * dev)479 int mlx5_reclaim_startup_pages(struct mlx5_core_dev *dev)
480 {
481 	unsigned long end = jiffies + msecs_to_jiffies(MAX_RECLAIM_TIME_MSECS);
482 	struct fw_page *fwp;
483 	struct rb_node *p;
484 	int nclaimed = 0;
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);
491 			err = reclaim_pages(dev, fwp->func_id,
492 					    optimal_reclaimed_pages(),
493 					    &nclaimed);
494 			if (err) {
495 				mlx5_core_warn(dev, "failed reclaiming pages (%d)\n",
496 					       err);
497 				return err;
498 			}
499 			if (nclaimed)
500 				end = jiffies + msecs_to_jiffies(MAX_RECLAIM_TIME_MSECS);
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 
mlx5_pagealloc_init(struct mlx5_core_dev * dev)511 void mlx5_pagealloc_init(struct mlx5_core_dev *dev)
512 {
513 	dev->priv.page_root = RB_ROOT;
514 	INIT_LIST_HEAD(&dev->priv.free_list);
515 }
516 
mlx5_pagealloc_cleanup(struct mlx5_core_dev * dev)517 void mlx5_pagealloc_cleanup(struct mlx5_core_dev *dev)
518 {
519 	/* nothing */
520 }
521 
mlx5_pagealloc_start(struct mlx5_core_dev * dev)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 
mlx5_pagealloc_stop(struct mlx5_core_dev * dev)531 void mlx5_pagealloc_stop(struct mlx5_core_dev *dev)
532 {
533 	destroy_workqueue(dev->priv.pg_wq);
534 }
535