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 <linux/highmem.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 }
278 
page_notify_fail(struct mlx5_core_dev * dev,u16 func_id)279 static void page_notify_fail(struct mlx5_core_dev *dev, u16 func_id)
280 {
281 	struct mlx5_manage_pages_inbox *in;
282 	struct mlx5_manage_pages_outbox out;
283 	int err;
284 
285 	in = kzalloc(sizeof(*in), GFP_KERNEL);
286 	if (!in)
287 		return;
288 
289 	memset(&out, 0, sizeof(out));
290 	in->hdr.opcode = cpu_to_be16(MLX5_CMD_OP_MANAGE_PAGES);
291 	in->hdr.opmod = cpu_to_be16(MLX5_PAGES_CANT_GIVE);
292 	in->func_id = cpu_to_be16(func_id);
293 	err = mlx5_cmd_exec(dev, in, sizeof(*in), &out, sizeof(out));
294 	if (!err)
295 		err = mlx5_cmd_status_to_err(&out.hdr);
296 
297 	if (err)
298 		mlx5_core_warn(dev, "page notify failed\n");
299 
300 	kfree(in);
301 }
302 
give_pages(struct mlx5_core_dev * dev,u16 func_id,int npages,int notify_fail)303 static int give_pages(struct mlx5_core_dev *dev, u16 func_id, int npages,
304 		      int notify_fail)
305 {
306 	struct mlx5_manage_pages_inbox *in;
307 	struct mlx5_manage_pages_outbox out;
308 	int inlen;
309 	u64 addr;
310 	int err;
311 	int i;
312 
313 	inlen = sizeof(*in) + npages * sizeof(in->pas[0]);
314 	in = mlx5_vzalloc(inlen);
315 	if (!in) {
316 		err = -ENOMEM;
317 		mlx5_core_warn(dev, "vzalloc failed %d\n", inlen);
318 		goto out_free;
319 	}
320 	memset(&out, 0, sizeof(out));
321 
322 	for (i = 0; i < npages; i++) {
323 retry:
324 		err = alloc_4k(dev, &addr);
325 		if (err) {
326 			if (err == -ENOMEM)
327 				err = alloc_system_page(dev, func_id);
328 			if (err)
329 				goto out_4k;
330 
331 			goto retry;
332 		}
333 		in->pas[i] = cpu_to_be64(addr);
334 	}
335 
336 	in->hdr.opcode = cpu_to_be16(MLX5_CMD_OP_MANAGE_PAGES);
337 	in->hdr.opmod = cpu_to_be16(MLX5_PAGES_GIVE);
338 	in->func_id = cpu_to_be16(func_id);
339 	in->num_entries = cpu_to_be32(npages);
340 	err = mlx5_cmd_exec(dev, in, inlen, &out, sizeof(out));
341 	if (err) {
342 		mlx5_core_warn(dev, "func_id 0x%x, npages %d, err %d\n",
343 			       func_id, npages, err);
344 		goto out_4k;
345 	}
346 	dev->priv.fw_pages += npages;
347 
348 	err = mlx5_cmd_status_to_err(&out.hdr);
349 	if (err) {
350 		mlx5_core_warn(dev, "func_id 0x%x, npages %d, status %d\n",
351 			       func_id, npages, out.hdr.status);
352 		goto out_4k;
353 	}
354 
355 	mlx5_core_dbg(dev, "err %d\n", err);
356 
357 	kvfree(in);
358 	return 0;
359 
360 out_4k:
361 	for (i--; i >= 0; i--)
362 		free_4k(dev, be64_to_cpu(in->pas[i]));
363 out_free:
364 	kvfree(in);
365 	if (notify_fail)
366 		page_notify_fail(dev, func_id);
367 	return err;
368 }
369 
reclaim_pages(struct mlx5_core_dev * dev,u32 func_id,int npages,int * nclaimed)370 static int reclaim_pages(struct mlx5_core_dev *dev, u32 func_id, int npages,
371 			 int *nclaimed)
372 {
373 	struct mlx5_manage_pages_inbox   in;
374 	struct mlx5_manage_pages_outbox *out;
375 	int num_claimed;
376 	int outlen;
377 	u64 addr;
378 	int err;
379 	int i;
380 
381 	if (nclaimed)
382 		*nclaimed = 0;
383 
384 	memset(&in, 0, sizeof(in));
385 	outlen = sizeof(*out) + npages * sizeof(out->pas[0]);
386 	out = mlx5_vzalloc(outlen);
387 	if (!out)
388 		return -ENOMEM;
389 
390 	in.hdr.opcode = cpu_to_be16(MLX5_CMD_OP_MANAGE_PAGES);
391 	in.hdr.opmod = cpu_to_be16(MLX5_PAGES_TAKE);
392 	in.func_id = cpu_to_be16(func_id);
393 	in.num_entries = cpu_to_be32(npages);
394 	mlx5_core_dbg(dev, "npages %d, outlen %d\n", npages, outlen);
395 	err = mlx5_cmd_exec(dev, &in, sizeof(in), out, outlen);
396 	if (err) {
397 		mlx5_core_err(dev, "failed reclaiming pages\n");
398 		goto out_free;
399 	}
400 	dev->priv.fw_pages -= npages;
401 
402 	if (out->hdr.status) {
403 		err = mlx5_cmd_status_to_err(&out->hdr);
404 		goto out_free;
405 	}
406 
407 	num_claimed = be32_to_cpu(out->num_entries);
408 	if (nclaimed)
409 		*nclaimed = num_claimed;
410 
411 	for (i = 0; i < num_claimed; i++) {
412 		addr = be64_to_cpu(out->pas[i]);
413 		free_4k(dev, addr);
414 	}
415 
416 out_free:
417 	kvfree(out);
418 	return err;
419 }
420 
pages_work_handler(struct work_struct * work)421 static void pages_work_handler(struct work_struct *work)
422 {
423 	struct mlx5_pages_req *req = container_of(work, struct mlx5_pages_req, work);
424 	struct mlx5_core_dev *dev = req->dev;
425 	int err = 0;
426 
427 	if (req->npages < 0)
428 		err = reclaim_pages(dev, req->func_id, -1 * req->npages, NULL);
429 	else if (req->npages > 0)
430 		err = give_pages(dev, req->func_id, req->npages, 1);
431 
432 	if (err)
433 		mlx5_core_warn(dev, "%s fail %d\n",
434 			       req->npages < 0 ? "reclaim" : "give", err);
435 
436 	kfree(req);
437 }
438 
mlx5_core_req_pages_handler(struct mlx5_core_dev * dev,u16 func_id,s32 npages)439 void mlx5_core_req_pages_handler(struct mlx5_core_dev *dev, u16 func_id,
440 				 s32 npages)
441 {
442 	struct mlx5_pages_req *req;
443 
444 	req = kzalloc(sizeof(*req), GFP_ATOMIC);
445 	if (!req) {
446 		mlx5_core_warn(dev, "failed to allocate pages request\n");
447 		return;
448 	}
449 
450 	req->dev = dev;
451 	req->func_id = func_id;
452 	req->npages = npages;
453 	INIT_WORK(&req->work, pages_work_handler);
454 	queue_work(dev->priv.pg_wq, &req->work);
455 }
456 
mlx5_satisfy_startup_pages(struct mlx5_core_dev * dev,int boot)457 int mlx5_satisfy_startup_pages(struct mlx5_core_dev *dev, int boot)
458 {
459 	u16 uninitialized_var(func_id);
460 	s32 uninitialized_var(npages);
461 	int err;
462 
463 	err = mlx5_cmd_query_pages(dev, &func_id, &npages, boot);
464 	if (err)
465 		return err;
466 
467 	mlx5_core_dbg(dev, "requested %d %s pages for func_id 0x%x\n",
468 		      npages, boot ? "boot" : "init", func_id);
469 
470 	return give_pages(dev, func_id, npages, 0);
471 }
472 
473 enum {
474 	MLX5_BLKS_FOR_RECLAIM_PAGES = 12
475 };
476 
optimal_reclaimed_pages(void)477 static int optimal_reclaimed_pages(void)
478 {
479 	struct mlx5_cmd_prot_block *block;
480 	struct mlx5_cmd_layout *lay;
481 	int ret;
482 
483 	ret = (sizeof(lay->out) + MLX5_BLKS_FOR_RECLAIM_PAGES * sizeof(block->data) -
484 	       sizeof(struct mlx5_manage_pages_outbox)) /
485 	       FIELD_SIZEOF(struct mlx5_manage_pages_outbox, pas[0]);
486 
487 	return ret;
488 }
489 
mlx5_reclaim_startup_pages(struct mlx5_core_dev * dev)490 int mlx5_reclaim_startup_pages(struct mlx5_core_dev *dev)
491 {
492 	unsigned long end = jiffies + msecs_to_jiffies(MAX_RECLAIM_TIME_MSECS);
493 	struct fw_page *fwp;
494 	struct rb_node *p;
495 	int nclaimed = 0;
496 	int err = 0;
497 
498 	do {
499 		p = rb_first(&dev->priv.page_root);
500 		if (p) {
501 			fwp = rb_entry(p, struct fw_page, rb_node);
502 			if (dev->state == MLX5_DEVICE_STATE_INTERNAL_ERROR) {
503 				free_4k(dev, fwp->addr);
504 				nclaimed = 1;
505 			} else {
506 				err = reclaim_pages(dev, fwp->func_id,
507 						    optimal_reclaimed_pages(),
508 						    &nclaimed);
509 			}
510 			if (err) {
511 				mlx5_core_warn(dev, "failed reclaiming pages (%d)\n",
512 					       err);
513 				return err;
514 			}
515 			if (nclaimed)
516 				end = jiffies + msecs_to_jiffies(MAX_RECLAIM_TIME_MSECS);
517 		}
518 		if (time_after(jiffies, end)) {
519 			mlx5_core_warn(dev, "FW did not return all pages. giving up...\n");
520 			break;
521 		}
522 	} while (p);
523 
524 	return 0;
525 }
526 
mlx5_pagealloc_init(struct mlx5_core_dev * dev)527 void mlx5_pagealloc_init(struct mlx5_core_dev *dev)
528 {
529 	dev->priv.page_root = RB_ROOT;
530 	INIT_LIST_HEAD(&dev->priv.free_list);
531 }
532 
mlx5_pagealloc_cleanup(struct mlx5_core_dev * dev)533 void mlx5_pagealloc_cleanup(struct mlx5_core_dev *dev)
534 {
535 	/* nothing */
536 }
537 
mlx5_pagealloc_start(struct mlx5_core_dev * dev)538 int mlx5_pagealloc_start(struct mlx5_core_dev *dev)
539 {
540 	dev->priv.pg_wq = create_singlethread_workqueue("mlx5_page_allocator");
541 	if (!dev->priv.pg_wq)
542 		return -ENOMEM;
543 
544 	return 0;
545 }
546 
mlx5_pagealloc_stop(struct mlx5_core_dev * dev)547 void mlx5_pagealloc_stop(struct mlx5_core_dev *dev)
548 {
549 	destroy_workqueue(dev->priv.pg_wq);
550 }
551