cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

pagealloc.c (19927B)


      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/delay.h>
     36#include <linux/mlx5/driver.h>
     37#include <linux/xarray.h>
     38#include "mlx5_core.h"
     39#include "lib/eq.h"
     40#include "lib/tout.h"
     41
     42enum {
     43	MLX5_PAGES_CANT_GIVE	= 0,
     44	MLX5_PAGES_GIVE		= 1,
     45	MLX5_PAGES_TAKE		= 2
     46};
     47
     48struct mlx5_pages_req {
     49	struct mlx5_core_dev *dev;
     50	u16	func_id;
     51	u8	ec_function;
     52	s32	npages;
     53	struct work_struct work;
     54	u8	release_all;
     55};
     56
     57struct fw_page {
     58	struct rb_node		rb_node;
     59	u64			addr;
     60	struct page	       *page;
     61	u32			function;
     62	unsigned long		bitmask;
     63	struct list_head	list;
     64	unsigned int free_count;
     65};
     66
     67enum {
     68	MLX5_MAX_RECLAIM_TIME_MILI	= 5000,
     69	MLX5_NUM_4K_IN_PAGE		= PAGE_SIZE / MLX5_ADAPTER_PAGE_SIZE,
     70};
     71
     72static u32 get_function(u16 func_id, bool ec_function)
     73{
     74	return (u32)func_id | (ec_function << 16);
     75}
     76
     77static struct rb_root *page_root_per_function(struct mlx5_core_dev *dev, u32 function)
     78{
     79	struct rb_root *root;
     80	int err;
     81
     82	root = xa_load(&dev->priv.page_root_xa, function);
     83	if (root)
     84		return root;
     85
     86	root = kzalloc(sizeof(*root), GFP_KERNEL);
     87	if (!root)
     88		return ERR_PTR(-ENOMEM);
     89
     90	err = xa_insert(&dev->priv.page_root_xa, function, root, GFP_KERNEL);
     91	if (err) {
     92		kfree(root);
     93		return ERR_PTR(err);
     94	}
     95
     96	*root = RB_ROOT;
     97
     98	return root;
     99}
    100
    101static int insert_page(struct mlx5_core_dev *dev, u64 addr, struct page *page, u32 function)
    102{
    103	struct rb_node *parent = NULL;
    104	struct rb_root *root;
    105	struct rb_node **new;
    106	struct fw_page *nfp;
    107	struct fw_page *tfp;
    108	int i;
    109
    110	root = page_root_per_function(dev, function);
    111	if (IS_ERR(root))
    112		return PTR_ERR(root);
    113
    114	new = &root->rb_node;
    115
    116	while (*new) {
    117		parent = *new;
    118		tfp = rb_entry(parent, struct fw_page, rb_node);
    119		if (tfp->addr < addr)
    120			new = &parent->rb_left;
    121		else if (tfp->addr > addr)
    122			new = &parent->rb_right;
    123		else
    124			return -EEXIST;
    125	}
    126
    127	nfp = kzalloc(sizeof(*nfp), GFP_KERNEL);
    128	if (!nfp)
    129		return -ENOMEM;
    130
    131	nfp->addr = addr;
    132	nfp->page = page;
    133	nfp->function = function;
    134	nfp->free_count = MLX5_NUM_4K_IN_PAGE;
    135	for (i = 0; i < MLX5_NUM_4K_IN_PAGE; i++)
    136		set_bit(i, &nfp->bitmask);
    137
    138	rb_link_node(&nfp->rb_node, parent, new);
    139	rb_insert_color(&nfp->rb_node, root);
    140	list_add(&nfp->list, &dev->priv.free_list);
    141
    142	return 0;
    143}
    144
    145static struct fw_page *find_fw_page(struct mlx5_core_dev *dev, u64 addr,
    146				    u32 function)
    147{
    148	struct fw_page *result = NULL;
    149	struct rb_root *root;
    150	struct rb_node *tmp;
    151	struct fw_page *tfp;
    152
    153	root = xa_load(&dev->priv.page_root_xa, function);
    154	if (WARN_ON_ONCE(!root))
    155		return NULL;
    156
    157	tmp = root->rb_node;
    158
    159	while (tmp) {
    160		tfp = rb_entry(tmp, struct fw_page, rb_node);
    161		if (tfp->addr < addr) {
    162			tmp = tmp->rb_left;
    163		} else if (tfp->addr > addr) {
    164			tmp = tmp->rb_right;
    165		} else {
    166			result = tfp;
    167			break;
    168		}
    169	}
    170
    171	return result;
    172}
    173
    174static int mlx5_cmd_query_pages(struct mlx5_core_dev *dev, u16 *func_id,
    175				s32 *npages, int boot)
    176{
    177	u32 out[MLX5_ST_SZ_DW(query_pages_out)] = {};
    178	u32 in[MLX5_ST_SZ_DW(query_pages_in)] = {};
    179	int err;
    180
    181	MLX5_SET(query_pages_in, in, opcode, MLX5_CMD_OP_QUERY_PAGES);
    182	MLX5_SET(query_pages_in, in, op_mod, boot ?
    183		 MLX5_QUERY_PAGES_IN_OP_MOD_BOOT_PAGES :
    184		 MLX5_QUERY_PAGES_IN_OP_MOD_INIT_PAGES);
    185	MLX5_SET(query_pages_in, in, embedded_cpu_function, mlx5_core_is_ecpf(dev));
    186
    187	err = mlx5_cmd_exec_inout(dev, query_pages, in, out);
    188	if (err)
    189		return err;
    190
    191	*npages = MLX5_GET(query_pages_out, out, num_pages);
    192	*func_id = MLX5_GET(query_pages_out, out, function_id);
    193
    194	return err;
    195}
    196
    197static int alloc_4k(struct mlx5_core_dev *dev, u64 *addr, u32 function)
    198{
    199	struct fw_page *fp = NULL;
    200	struct fw_page *iter;
    201	unsigned n;
    202
    203	list_for_each_entry(iter, &dev->priv.free_list, list) {
    204		if (iter->function != function)
    205			continue;
    206		fp = iter;
    207	}
    208
    209	if (list_empty(&dev->priv.free_list) || !fp)
    210		return -ENOMEM;
    211
    212	n = find_first_bit(&fp->bitmask, 8 * sizeof(fp->bitmask));
    213	if (n >= MLX5_NUM_4K_IN_PAGE) {
    214		mlx5_core_warn(dev, "alloc 4k bug\n");
    215		return -ENOENT;
    216	}
    217	clear_bit(n, &fp->bitmask);
    218	fp->free_count--;
    219	if (!fp->free_count)
    220		list_del(&fp->list);
    221
    222	*addr = fp->addr + n * MLX5_ADAPTER_PAGE_SIZE;
    223
    224	return 0;
    225}
    226
    227#define MLX5_U64_4K_PAGE_MASK ((~(u64)0U) << PAGE_SHIFT)
    228
    229static void free_fwp(struct mlx5_core_dev *dev, struct fw_page *fwp,
    230		     bool in_free_list)
    231{
    232	struct rb_root *root;
    233
    234	root = xa_load(&dev->priv.page_root_xa, fwp->function);
    235	if (WARN_ON_ONCE(!root))
    236		return;
    237
    238	rb_erase(&fwp->rb_node, root);
    239	if (in_free_list)
    240		list_del(&fwp->list);
    241	dma_unmap_page(mlx5_core_dma_dev(dev), fwp->addr & MLX5_U64_4K_PAGE_MASK,
    242		       PAGE_SIZE, DMA_BIDIRECTIONAL);
    243	__free_page(fwp->page);
    244	kfree(fwp);
    245}
    246
    247static void free_4k(struct mlx5_core_dev *dev, u64 addr, u32 function)
    248{
    249	struct fw_page *fwp;
    250	int n;
    251
    252	fwp = find_fw_page(dev, addr & MLX5_U64_4K_PAGE_MASK, function);
    253	if (!fwp) {
    254		mlx5_core_warn_rl(dev, "page not found\n");
    255		return;
    256	}
    257	n = (addr & ~MLX5_U64_4K_PAGE_MASK) >> MLX5_ADAPTER_PAGE_SHIFT;
    258	fwp->free_count++;
    259	set_bit(n, &fwp->bitmask);
    260	if (fwp->free_count == MLX5_NUM_4K_IN_PAGE)
    261		free_fwp(dev, fwp, fwp->free_count != 1);
    262	else if (fwp->free_count == 1)
    263		list_add(&fwp->list, &dev->priv.free_list);
    264}
    265
    266static int alloc_system_page(struct mlx5_core_dev *dev, u32 function)
    267{
    268	struct device *device = mlx5_core_dma_dev(dev);
    269	int nid = dev_to_node(device);
    270	struct page *page;
    271	u64 zero_addr = 1;
    272	u64 addr;
    273	int err;
    274
    275	page = alloc_pages_node(nid, GFP_HIGHUSER, 0);
    276	if (!page) {
    277		mlx5_core_warn(dev, "failed to allocate page\n");
    278		return -ENOMEM;
    279	}
    280map:
    281	addr = dma_map_page(device, page, 0, PAGE_SIZE, DMA_BIDIRECTIONAL);
    282	if (dma_mapping_error(device, addr)) {
    283		mlx5_core_warn(dev, "failed dma mapping page\n");
    284		err = -ENOMEM;
    285		goto err_mapping;
    286	}
    287
    288	/* Firmware doesn't support page with physical address 0 */
    289	if (addr == 0) {
    290		zero_addr = addr;
    291		goto map;
    292	}
    293
    294	err = insert_page(dev, addr, page, function);
    295	if (err) {
    296		mlx5_core_err(dev, "failed to track allocated page\n");
    297		dma_unmap_page(device, addr, PAGE_SIZE, DMA_BIDIRECTIONAL);
    298	}
    299
    300err_mapping:
    301	if (err)
    302		__free_page(page);
    303
    304	if (zero_addr == 0)
    305		dma_unmap_page(device, zero_addr, PAGE_SIZE,
    306			       DMA_BIDIRECTIONAL);
    307
    308	return err;
    309}
    310
    311static void page_notify_fail(struct mlx5_core_dev *dev, u16 func_id,
    312			     bool ec_function)
    313{
    314	u32 in[MLX5_ST_SZ_DW(manage_pages_in)] = {};
    315	int err;
    316
    317	MLX5_SET(manage_pages_in, in, opcode, MLX5_CMD_OP_MANAGE_PAGES);
    318	MLX5_SET(manage_pages_in, in, op_mod, MLX5_PAGES_CANT_GIVE);
    319	MLX5_SET(manage_pages_in, in, function_id, func_id);
    320	MLX5_SET(manage_pages_in, in, embedded_cpu_function, ec_function);
    321
    322	err = mlx5_cmd_exec_in(dev, manage_pages, in);
    323	if (err)
    324		mlx5_core_warn(dev, "page notify failed func_id(%d) err(%d)\n",
    325			       func_id, err);
    326}
    327
    328static int give_pages(struct mlx5_core_dev *dev, u16 func_id, int npages,
    329		      int event, bool ec_function)
    330{
    331	u32 function = get_function(func_id, ec_function);
    332	u32 out[MLX5_ST_SZ_DW(manage_pages_out)] = {0};
    333	int inlen = MLX5_ST_SZ_BYTES(manage_pages_in);
    334	int notify_fail = event;
    335	u64 addr;
    336	int err;
    337	u32 *in;
    338	int i;
    339
    340	inlen += npages * MLX5_FLD_SZ_BYTES(manage_pages_in, pas[0]);
    341	in = kvzalloc(inlen, GFP_KERNEL);
    342	if (!in) {
    343		err = -ENOMEM;
    344		mlx5_core_warn(dev, "vzalloc failed %d\n", inlen);
    345		goto out_free;
    346	}
    347
    348	for (i = 0; i < npages; i++) {
    349retry:
    350		err = alloc_4k(dev, &addr, function);
    351		if (err) {
    352			if (err == -ENOMEM)
    353				err = alloc_system_page(dev, function);
    354			if (err) {
    355				dev->priv.fw_pages_alloc_failed += (npages - i);
    356				goto out_4k;
    357			}
    358
    359			goto retry;
    360		}
    361		MLX5_ARRAY_SET64(manage_pages_in, in, pas, i, addr);
    362	}
    363
    364	MLX5_SET(manage_pages_in, in, opcode, MLX5_CMD_OP_MANAGE_PAGES);
    365	MLX5_SET(manage_pages_in, in, op_mod, MLX5_PAGES_GIVE);
    366	MLX5_SET(manage_pages_in, in, function_id, func_id);
    367	MLX5_SET(manage_pages_in, in, input_num_entries, npages);
    368	MLX5_SET(manage_pages_in, in, embedded_cpu_function, ec_function);
    369
    370	err = mlx5_cmd_do(dev, in, inlen, out, sizeof(out));
    371	if (err == -EREMOTEIO) {
    372		notify_fail = 0;
    373		/* if triggered by FW and failed by FW ignore */
    374		if (event) {
    375			err = 0;
    376			goto out_dropped;
    377		}
    378	}
    379	if (err) {
    380		err = mlx5_cmd_check(dev, err, in, out);
    381		mlx5_core_warn(dev, "func_id 0x%x, npages %d, err %d\n",
    382			       func_id, npages, err);
    383		goto out_dropped;
    384	}
    385
    386	dev->priv.fw_pages += npages;
    387	if (func_id)
    388		dev->priv.vfs_pages += npages;
    389	else if (mlx5_core_is_ecpf(dev) && !ec_function)
    390		dev->priv.host_pf_pages += npages;
    391
    392	mlx5_core_dbg(dev, "npages %d, ec_function %d, func_id 0x%x, err %d\n",
    393		      npages, ec_function, func_id, err);
    394
    395	kvfree(in);
    396	return 0;
    397
    398out_dropped:
    399	dev->priv.give_pages_dropped += npages;
    400out_4k:
    401	for (i--; i >= 0; i--)
    402		free_4k(dev, MLX5_GET64(manage_pages_in, in, pas[i]), function);
    403out_free:
    404	kvfree(in);
    405	if (notify_fail)
    406		page_notify_fail(dev, func_id, ec_function);
    407	return err;
    408}
    409
    410static void release_all_pages(struct mlx5_core_dev *dev, u16 func_id,
    411			      bool ec_function)
    412{
    413	u32 function = get_function(func_id, ec_function);
    414	struct rb_root *root;
    415	struct rb_node *p;
    416	int npages = 0;
    417
    418	root = xa_load(&dev->priv.page_root_xa, function);
    419	if (WARN_ON_ONCE(!root))
    420		return;
    421
    422	p = rb_first(root);
    423	while (p) {
    424		struct fw_page *fwp = rb_entry(p, struct fw_page, rb_node);
    425
    426		p = rb_next(p);
    427		npages += (MLX5_NUM_4K_IN_PAGE - fwp->free_count);
    428		free_fwp(dev, fwp, fwp->free_count);
    429	}
    430
    431	dev->priv.fw_pages -= npages;
    432	if (func_id)
    433		dev->priv.vfs_pages -= npages;
    434	else if (mlx5_core_is_ecpf(dev) && !ec_function)
    435		dev->priv.host_pf_pages -= npages;
    436
    437	mlx5_core_dbg(dev, "npages %d, ec_function %d, func_id 0x%x\n",
    438		      npages, ec_function, func_id);
    439}
    440
    441static u32 fwp_fill_manage_pages_out(struct fw_page *fwp, u32 *out, u32 index,
    442				     u32 npages)
    443{
    444	u32 pages_set = 0;
    445	unsigned int n;
    446
    447	for_each_clear_bit(n, &fwp->bitmask, MLX5_NUM_4K_IN_PAGE) {
    448		MLX5_ARRAY_SET64(manage_pages_out, out, pas, index + pages_set,
    449				 fwp->addr + (n * MLX5_ADAPTER_PAGE_SIZE));
    450		pages_set++;
    451
    452		if (!--npages)
    453			break;
    454	}
    455
    456	return pages_set;
    457}
    458
    459static int reclaim_pages_cmd(struct mlx5_core_dev *dev,
    460			     u32 *in, int in_size, u32 *out, int out_size)
    461{
    462	struct rb_root *root;
    463	struct fw_page *fwp;
    464	struct rb_node *p;
    465	bool ec_function;
    466	u32 func_id;
    467	u32 npages;
    468	u32 i = 0;
    469
    470	if (!mlx5_cmd_is_down(dev))
    471		return mlx5_cmd_do(dev, in, in_size, out, out_size);
    472
    473	/* No hard feelings, we want our pages back! */
    474	npages = MLX5_GET(manage_pages_in, in, input_num_entries);
    475	func_id = MLX5_GET(manage_pages_in, in, function_id);
    476	ec_function = MLX5_GET(manage_pages_in, in, embedded_cpu_function);
    477
    478	root = xa_load(&dev->priv.page_root_xa, get_function(func_id, ec_function));
    479	if (WARN_ON_ONCE(!root))
    480		return -EEXIST;
    481
    482	p = rb_first(root);
    483	while (p && i < npages) {
    484		fwp = rb_entry(p, struct fw_page, rb_node);
    485		p = rb_next(p);
    486
    487		i += fwp_fill_manage_pages_out(fwp, out, i, npages - i);
    488	}
    489
    490	MLX5_SET(manage_pages_out, out, output_num_entries, i);
    491	return 0;
    492}
    493
    494static int reclaim_pages(struct mlx5_core_dev *dev, u16 func_id, int npages,
    495			 int *nclaimed, bool event, bool ec_function)
    496{
    497	u32 function = get_function(func_id, ec_function);
    498	int outlen = MLX5_ST_SZ_BYTES(manage_pages_out);
    499	u32 in[MLX5_ST_SZ_DW(manage_pages_in)] = {};
    500	int num_claimed;
    501	u32 *out;
    502	int err;
    503	int i;
    504
    505	if (nclaimed)
    506		*nclaimed = 0;
    507
    508	outlen += npages * MLX5_FLD_SZ_BYTES(manage_pages_out, pas[0]);
    509	out = kvzalloc(outlen, GFP_KERNEL);
    510	if (!out)
    511		return -ENOMEM;
    512
    513	MLX5_SET(manage_pages_in, in, opcode, MLX5_CMD_OP_MANAGE_PAGES);
    514	MLX5_SET(manage_pages_in, in, op_mod, MLX5_PAGES_TAKE);
    515	MLX5_SET(manage_pages_in, in, function_id, func_id);
    516	MLX5_SET(manage_pages_in, in, input_num_entries, npages);
    517	MLX5_SET(manage_pages_in, in, embedded_cpu_function, ec_function);
    518
    519	mlx5_core_dbg(dev, "func 0x%x, npages %d, outlen %d\n",
    520		      func_id, npages, outlen);
    521	err = reclaim_pages_cmd(dev, in, sizeof(in), out, outlen);
    522	if (err) {
    523		npages = MLX5_GET(manage_pages_in, in, input_num_entries);
    524		dev->priv.reclaim_pages_discard += npages;
    525	}
    526	/* if triggered by FW event and failed by FW then ignore */
    527	if (event && err == -EREMOTEIO)
    528		err = 0;
    529	if (err) {
    530		err = mlx5_cmd_check(dev, err, in, out);
    531		mlx5_core_err(dev, "failed reclaiming pages: err %d\n", err);
    532		goto out_free;
    533	}
    534
    535	num_claimed = MLX5_GET(manage_pages_out, out, output_num_entries);
    536	if (num_claimed > npages) {
    537		mlx5_core_warn(dev, "fw returned %d, driver asked %d => corruption\n",
    538			       num_claimed, npages);
    539		err = -EINVAL;
    540		goto out_free;
    541	}
    542
    543	for (i = 0; i < num_claimed; i++)
    544		free_4k(dev, MLX5_GET64(manage_pages_out, out, pas[i]), function);
    545
    546	if (nclaimed)
    547		*nclaimed = num_claimed;
    548
    549	dev->priv.fw_pages -= num_claimed;
    550	if (func_id)
    551		dev->priv.vfs_pages -= num_claimed;
    552	else if (mlx5_core_is_ecpf(dev) && !ec_function)
    553		dev->priv.host_pf_pages -= num_claimed;
    554
    555out_free:
    556	kvfree(out);
    557	return err;
    558}
    559
    560static void pages_work_handler(struct work_struct *work)
    561{
    562	struct mlx5_pages_req *req = container_of(work, struct mlx5_pages_req, work);
    563	struct mlx5_core_dev *dev = req->dev;
    564	int err = 0;
    565
    566	if (req->release_all)
    567		release_all_pages(dev, req->func_id, req->ec_function);
    568	else if (req->npages < 0)
    569		err = reclaim_pages(dev, req->func_id, -1 * req->npages, NULL,
    570				    true, req->ec_function);
    571	else if (req->npages > 0)
    572		err = give_pages(dev, req->func_id, req->npages, 1, req->ec_function);
    573
    574	if (err)
    575		mlx5_core_warn(dev, "%s fail %d\n",
    576			       req->npages < 0 ? "reclaim" : "give", err);
    577
    578	kfree(req);
    579}
    580
    581enum {
    582	EC_FUNCTION_MASK = 0x8000,
    583	RELEASE_ALL_PAGES_MASK = 0x4000,
    584};
    585
    586static int req_pages_handler(struct notifier_block *nb,
    587			     unsigned long type, void *data)
    588{
    589	struct mlx5_pages_req *req;
    590	struct mlx5_core_dev *dev;
    591	struct mlx5_priv *priv;
    592	struct mlx5_eqe *eqe;
    593	bool ec_function;
    594	bool release_all;
    595	u16 func_id;
    596	s32 npages;
    597
    598	priv = mlx5_nb_cof(nb, struct mlx5_priv, pg_nb);
    599	dev  = container_of(priv, struct mlx5_core_dev, priv);
    600	eqe  = data;
    601
    602	func_id = be16_to_cpu(eqe->data.req_pages.func_id);
    603	npages  = be32_to_cpu(eqe->data.req_pages.num_pages);
    604	ec_function = be16_to_cpu(eqe->data.req_pages.ec_function) & EC_FUNCTION_MASK;
    605	release_all = be16_to_cpu(eqe->data.req_pages.ec_function) &
    606		      RELEASE_ALL_PAGES_MASK;
    607	mlx5_core_dbg(dev, "page request for func 0x%x, npages %d, release_all %d\n",
    608		      func_id, npages, release_all);
    609	req = kzalloc(sizeof(*req), GFP_ATOMIC);
    610	if (!req) {
    611		mlx5_core_warn(dev, "failed to allocate pages request\n");
    612		return NOTIFY_DONE;
    613	}
    614
    615	req->dev = dev;
    616	req->func_id = func_id;
    617	req->npages = npages;
    618	req->ec_function = ec_function;
    619	req->release_all = release_all;
    620	INIT_WORK(&req->work, pages_work_handler);
    621	queue_work(dev->priv.pg_wq, &req->work);
    622	return NOTIFY_OK;
    623}
    624
    625int mlx5_satisfy_startup_pages(struct mlx5_core_dev *dev, int boot)
    626{
    627	u16 func_id;
    628	s32 npages;
    629	int err;
    630
    631	err = mlx5_cmd_query_pages(dev, &func_id, &npages, boot);
    632	if (err)
    633		return err;
    634
    635	mlx5_core_dbg(dev, "requested %d %s pages for func_id 0x%x\n",
    636		      npages, boot ? "boot" : "init", func_id);
    637
    638	return give_pages(dev, func_id, npages, 0, mlx5_core_is_ecpf(dev));
    639}
    640
    641enum {
    642	MLX5_BLKS_FOR_RECLAIM_PAGES = 12
    643};
    644
    645static int optimal_reclaimed_pages(void)
    646{
    647	struct mlx5_cmd_prot_block *block;
    648	struct mlx5_cmd_layout *lay;
    649	int ret;
    650
    651	ret = (sizeof(lay->out) + MLX5_BLKS_FOR_RECLAIM_PAGES * sizeof(block->data) -
    652	       MLX5_ST_SZ_BYTES(manage_pages_out)) /
    653	       MLX5_FLD_SZ_BYTES(manage_pages_out, pas[0]);
    654
    655	return ret;
    656}
    657
    658static int mlx5_reclaim_root_pages(struct mlx5_core_dev *dev,
    659				   struct rb_root *root, u16 func_id)
    660{
    661	u64 recl_pages_to_jiffies = msecs_to_jiffies(mlx5_tout_ms(dev, RECLAIM_PAGES));
    662	unsigned long end = jiffies + recl_pages_to_jiffies;
    663
    664	while (!RB_EMPTY_ROOT(root)) {
    665		int nclaimed;
    666		int err;
    667
    668		err = reclaim_pages(dev, func_id, optimal_reclaimed_pages(),
    669				    &nclaimed, false, mlx5_core_is_ecpf(dev));
    670		if (err) {
    671			mlx5_core_warn(dev, "failed reclaiming pages (%d) for func id 0x%x\n",
    672				       err, func_id);
    673			return err;
    674		}
    675
    676		if (nclaimed)
    677			end = jiffies + recl_pages_to_jiffies;
    678
    679		if (time_after(jiffies, end)) {
    680			mlx5_core_warn(dev, "FW did not return all pages. giving up...\n");
    681			break;
    682		}
    683	}
    684
    685	return 0;
    686}
    687
    688int mlx5_reclaim_startup_pages(struct mlx5_core_dev *dev)
    689{
    690	struct rb_root *root;
    691	unsigned long id;
    692	void *entry;
    693
    694	xa_for_each(&dev->priv.page_root_xa, id, entry) {
    695		root = entry;
    696		mlx5_reclaim_root_pages(dev, root, id);
    697		xa_erase(&dev->priv.page_root_xa, id);
    698		kfree(root);
    699	}
    700
    701	WARN_ON(!xa_empty(&dev->priv.page_root_xa));
    702
    703	WARN(dev->priv.fw_pages,
    704	     "FW pages counter is %d after reclaiming all pages\n",
    705	     dev->priv.fw_pages);
    706	WARN(dev->priv.vfs_pages,
    707	     "VFs FW pages counter is %d after reclaiming all pages\n",
    708	     dev->priv.vfs_pages);
    709	WARN(dev->priv.host_pf_pages,
    710	     "External host PF FW pages counter is %d after reclaiming all pages\n",
    711	     dev->priv.host_pf_pages);
    712
    713	return 0;
    714}
    715
    716int mlx5_pagealloc_init(struct mlx5_core_dev *dev)
    717{
    718	INIT_LIST_HEAD(&dev->priv.free_list);
    719	dev->priv.pg_wq = create_singlethread_workqueue("mlx5_page_allocator");
    720	if (!dev->priv.pg_wq)
    721		return -ENOMEM;
    722
    723	xa_init(&dev->priv.page_root_xa);
    724	mlx5_pages_debugfs_init(dev);
    725
    726	return 0;
    727}
    728
    729void mlx5_pagealloc_cleanup(struct mlx5_core_dev *dev)
    730{
    731	mlx5_pages_debugfs_cleanup(dev);
    732	xa_destroy(&dev->priv.page_root_xa);
    733	destroy_workqueue(dev->priv.pg_wq);
    734}
    735
    736void mlx5_pagealloc_start(struct mlx5_core_dev *dev)
    737{
    738	MLX5_NB_INIT(&dev->priv.pg_nb, req_pages_handler, PAGE_REQUEST);
    739	mlx5_eq_notifier_register(dev, &dev->priv.pg_nb);
    740}
    741
    742void mlx5_pagealloc_stop(struct mlx5_core_dev *dev)
    743{
    744	mlx5_eq_notifier_unregister(dev, &dev->priv.pg_nb);
    745	flush_workqueue(dev->priv.pg_wq);
    746}
    747
    748int mlx5_wait_for_pages(struct mlx5_core_dev *dev, int *pages)
    749{
    750	u64 recl_vf_pages_to_jiffies = msecs_to_jiffies(mlx5_tout_ms(dev, RECLAIM_VFS_PAGES));
    751	unsigned long end = jiffies + recl_vf_pages_to_jiffies;
    752	int prev_pages = *pages;
    753
    754	/* In case of internal error we will free the pages manually later */
    755	if (dev->state == MLX5_DEVICE_STATE_INTERNAL_ERROR) {
    756		mlx5_core_warn(dev, "Skipping wait for vf pages stage");
    757		return 0;
    758	}
    759
    760	mlx5_core_dbg(dev, "Waiting for %d pages\n", prev_pages);
    761	while (*pages) {
    762		if (time_after(jiffies, end)) {
    763			mlx5_core_warn(dev, "aborting while there are %d pending pages\n", *pages);
    764			return -ETIMEDOUT;
    765		}
    766		if (*pages < prev_pages) {
    767			end = jiffies + recl_vf_pages_to_jiffies;
    768			prev_pages = *pages;
    769		}
    770		msleep(50);
    771	}
    772
    773	mlx5_core_dbg(dev, "All pages received\n");
    774	return 0;
    775}