18c2ecf20Sopenharmony_ci/*
28c2ecf20Sopenharmony_ci * Copyright (c) 2013-2015, Mellanox Technologies. All rights reserved.
38c2ecf20Sopenharmony_ci *
48c2ecf20Sopenharmony_ci * This software is available to you under a choice of one of two
58c2ecf20Sopenharmony_ci * licenses.  You may choose to be licensed under the terms of the GNU
68c2ecf20Sopenharmony_ci * General Public License (GPL) Version 2, available from the file
78c2ecf20Sopenharmony_ci * COPYING in the main directory of this source tree, or the
88c2ecf20Sopenharmony_ci * OpenIB.org BSD license below:
98c2ecf20Sopenharmony_ci *
108c2ecf20Sopenharmony_ci *     Redistribution and use in source and binary forms, with or
118c2ecf20Sopenharmony_ci *     without modification, are permitted provided that the following
128c2ecf20Sopenharmony_ci *     conditions are met:
138c2ecf20Sopenharmony_ci *
148c2ecf20Sopenharmony_ci *      - Redistributions of source code must retain the above
158c2ecf20Sopenharmony_ci *        copyright notice, this list of conditions and the following
168c2ecf20Sopenharmony_ci *        disclaimer.
178c2ecf20Sopenharmony_ci *
188c2ecf20Sopenharmony_ci *      - Redistributions in binary form must reproduce the above
198c2ecf20Sopenharmony_ci *        copyright notice, this list of conditions and the following
208c2ecf20Sopenharmony_ci *        disclaimer in the documentation and/or other materials
218c2ecf20Sopenharmony_ci *        provided with the distribution.
228c2ecf20Sopenharmony_ci *
238c2ecf20Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
248c2ecf20Sopenharmony_ci * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
258c2ecf20Sopenharmony_ci * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
268c2ecf20Sopenharmony_ci * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
278c2ecf20Sopenharmony_ci * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
288c2ecf20Sopenharmony_ci * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
298c2ecf20Sopenharmony_ci * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
308c2ecf20Sopenharmony_ci * SOFTWARE.
318c2ecf20Sopenharmony_ci */
328c2ecf20Sopenharmony_ci
338c2ecf20Sopenharmony_ci
348c2ecf20Sopenharmony_ci#include <linux/kref.h>
358c2ecf20Sopenharmony_ci#include <linux/random.h>
368c2ecf20Sopenharmony_ci#include <linux/debugfs.h>
378c2ecf20Sopenharmony_ci#include <linux/export.h>
388c2ecf20Sopenharmony_ci#include <linux/delay.h>
398c2ecf20Sopenharmony_ci#include <rdma/ib_umem.h>
408c2ecf20Sopenharmony_ci#include <rdma/ib_umem_odp.h>
418c2ecf20Sopenharmony_ci#include <rdma/ib_verbs.h>
428c2ecf20Sopenharmony_ci#include "mlx5_ib.h"
438c2ecf20Sopenharmony_ci
448c2ecf20Sopenharmony_cienum {
458c2ecf20Sopenharmony_ci	MAX_PENDING_REG_MR = 8,
468c2ecf20Sopenharmony_ci};
478c2ecf20Sopenharmony_ci
488c2ecf20Sopenharmony_ci#define MLX5_UMR_ALIGN 2048
498c2ecf20Sopenharmony_ci
508c2ecf20Sopenharmony_cistatic void
518c2ecf20Sopenharmony_cicreate_mkey_callback(int status, struct mlx5_async_work *context);
528c2ecf20Sopenharmony_ci
538c2ecf20Sopenharmony_cistatic void set_mkc_access_pd_addr_fields(void *mkc, int acc, u64 start_addr,
548c2ecf20Sopenharmony_ci					  struct ib_pd *pd)
558c2ecf20Sopenharmony_ci{
568c2ecf20Sopenharmony_ci	struct mlx5_ib_dev *dev = to_mdev(pd->device);
578c2ecf20Sopenharmony_ci
588c2ecf20Sopenharmony_ci	MLX5_SET(mkc, mkc, a, !!(acc & IB_ACCESS_REMOTE_ATOMIC));
598c2ecf20Sopenharmony_ci	MLX5_SET(mkc, mkc, rw, !!(acc & IB_ACCESS_REMOTE_WRITE));
608c2ecf20Sopenharmony_ci	MLX5_SET(mkc, mkc, rr, !!(acc & IB_ACCESS_REMOTE_READ));
618c2ecf20Sopenharmony_ci	MLX5_SET(mkc, mkc, lw, !!(acc & IB_ACCESS_LOCAL_WRITE));
628c2ecf20Sopenharmony_ci	MLX5_SET(mkc, mkc, lr, 1);
638c2ecf20Sopenharmony_ci
648c2ecf20Sopenharmony_ci	if (MLX5_CAP_GEN(dev->mdev, relaxed_ordering_write))
658c2ecf20Sopenharmony_ci		MLX5_SET(mkc, mkc, relaxed_ordering_write,
668c2ecf20Sopenharmony_ci			 !!(acc & IB_ACCESS_RELAXED_ORDERING));
678c2ecf20Sopenharmony_ci	if (MLX5_CAP_GEN(dev->mdev, relaxed_ordering_read))
688c2ecf20Sopenharmony_ci		MLX5_SET(mkc, mkc, relaxed_ordering_read,
698c2ecf20Sopenharmony_ci			 !!(acc & IB_ACCESS_RELAXED_ORDERING));
708c2ecf20Sopenharmony_ci
718c2ecf20Sopenharmony_ci	MLX5_SET(mkc, mkc, pd, to_mpd(pd)->pdn);
728c2ecf20Sopenharmony_ci	MLX5_SET(mkc, mkc, qpn, 0xffffff);
738c2ecf20Sopenharmony_ci	MLX5_SET64(mkc, mkc, start_addr, start_addr);
748c2ecf20Sopenharmony_ci}
758c2ecf20Sopenharmony_ci
768c2ecf20Sopenharmony_cistatic void
778c2ecf20Sopenharmony_ciassign_mkey_variant(struct mlx5_ib_dev *dev, struct mlx5_core_mkey *mkey,
788c2ecf20Sopenharmony_ci		    u32 *in)
798c2ecf20Sopenharmony_ci{
808c2ecf20Sopenharmony_ci	u8 key = atomic_inc_return(&dev->mkey_var);
818c2ecf20Sopenharmony_ci	void *mkc;
828c2ecf20Sopenharmony_ci
838c2ecf20Sopenharmony_ci	mkc = MLX5_ADDR_OF(create_mkey_in, in, memory_key_mkey_entry);
848c2ecf20Sopenharmony_ci	MLX5_SET(mkc, mkc, mkey_7_0, key);
858c2ecf20Sopenharmony_ci	mkey->key = key;
868c2ecf20Sopenharmony_ci}
878c2ecf20Sopenharmony_ci
888c2ecf20Sopenharmony_cistatic int
898c2ecf20Sopenharmony_cimlx5_ib_create_mkey(struct mlx5_ib_dev *dev, struct mlx5_core_mkey *mkey,
908c2ecf20Sopenharmony_ci		    u32 *in, int inlen)
918c2ecf20Sopenharmony_ci{
928c2ecf20Sopenharmony_ci	assign_mkey_variant(dev, mkey, in);
938c2ecf20Sopenharmony_ci	return mlx5_core_create_mkey(dev->mdev, mkey, in, inlen);
948c2ecf20Sopenharmony_ci}
958c2ecf20Sopenharmony_ci
968c2ecf20Sopenharmony_cistatic int
978c2ecf20Sopenharmony_cimlx5_ib_create_mkey_cb(struct mlx5_ib_dev *dev,
988c2ecf20Sopenharmony_ci		       struct mlx5_core_mkey *mkey,
998c2ecf20Sopenharmony_ci		       struct mlx5_async_ctx *async_ctx,
1008c2ecf20Sopenharmony_ci		       u32 *in, int inlen, u32 *out, int outlen,
1018c2ecf20Sopenharmony_ci		       struct mlx5_async_work *context)
1028c2ecf20Sopenharmony_ci{
1038c2ecf20Sopenharmony_ci	MLX5_SET(create_mkey_in, in, opcode, MLX5_CMD_OP_CREATE_MKEY);
1048c2ecf20Sopenharmony_ci	assign_mkey_variant(dev, mkey, in);
1058c2ecf20Sopenharmony_ci	return mlx5_cmd_exec_cb(async_ctx, in, inlen, out, outlen,
1068c2ecf20Sopenharmony_ci				create_mkey_callback, context);
1078c2ecf20Sopenharmony_ci}
1088c2ecf20Sopenharmony_ci
1098c2ecf20Sopenharmony_cistatic void clean_mr(struct mlx5_ib_dev *dev, struct mlx5_ib_mr *mr);
1108c2ecf20Sopenharmony_cistatic void dereg_mr(struct mlx5_ib_dev *dev, struct mlx5_ib_mr *mr);
1118c2ecf20Sopenharmony_cistatic int mr_cache_max_order(struct mlx5_ib_dev *dev);
1128c2ecf20Sopenharmony_cistatic void queue_adjust_cache_locked(struct mlx5_cache_ent *ent);
1138c2ecf20Sopenharmony_ci
1148c2ecf20Sopenharmony_cistatic bool umr_can_use_indirect_mkey(struct mlx5_ib_dev *dev)
1158c2ecf20Sopenharmony_ci{
1168c2ecf20Sopenharmony_ci	return !MLX5_CAP_GEN(dev->mdev, umr_indirect_mkey_disabled);
1178c2ecf20Sopenharmony_ci}
1188c2ecf20Sopenharmony_ci
1198c2ecf20Sopenharmony_cistatic int destroy_mkey(struct mlx5_ib_dev *dev, struct mlx5_ib_mr *mr)
1208c2ecf20Sopenharmony_ci{
1218c2ecf20Sopenharmony_ci	WARN_ON(xa_load(&dev->odp_mkeys, mlx5_base_mkey(mr->mmkey.key)));
1228c2ecf20Sopenharmony_ci
1238c2ecf20Sopenharmony_ci	return mlx5_core_destroy_mkey(dev->mdev, &mr->mmkey);
1248c2ecf20Sopenharmony_ci}
1258c2ecf20Sopenharmony_ci
1268c2ecf20Sopenharmony_cistatic inline bool mlx5_ib_pas_fits_in_mr(struct mlx5_ib_mr *mr, u64 start,
1278c2ecf20Sopenharmony_ci					  u64 length)
1288c2ecf20Sopenharmony_ci{
1298c2ecf20Sopenharmony_ci	return ((u64)1 << mr->order) * MLX5_ADAPTER_PAGE_SIZE >=
1308c2ecf20Sopenharmony_ci		length + (start & (MLX5_ADAPTER_PAGE_SIZE - 1));
1318c2ecf20Sopenharmony_ci}
1328c2ecf20Sopenharmony_ci
1338c2ecf20Sopenharmony_cistatic void create_mkey_callback(int status, struct mlx5_async_work *context)
1348c2ecf20Sopenharmony_ci{
1358c2ecf20Sopenharmony_ci	struct mlx5_ib_mr *mr =
1368c2ecf20Sopenharmony_ci		container_of(context, struct mlx5_ib_mr, cb_work);
1378c2ecf20Sopenharmony_ci	struct mlx5_ib_dev *dev = mr->dev;
1388c2ecf20Sopenharmony_ci	struct mlx5_cache_ent *ent = mr->cache_ent;
1398c2ecf20Sopenharmony_ci	unsigned long flags;
1408c2ecf20Sopenharmony_ci
1418c2ecf20Sopenharmony_ci	if (status) {
1428c2ecf20Sopenharmony_ci		mlx5_ib_warn(dev, "async reg mr failed. status %d\n", status);
1438c2ecf20Sopenharmony_ci		kfree(mr);
1448c2ecf20Sopenharmony_ci		spin_lock_irqsave(&ent->lock, flags);
1458c2ecf20Sopenharmony_ci		ent->pending--;
1468c2ecf20Sopenharmony_ci		WRITE_ONCE(dev->fill_delay, 1);
1478c2ecf20Sopenharmony_ci		spin_unlock_irqrestore(&ent->lock, flags);
1488c2ecf20Sopenharmony_ci		mod_timer(&dev->delay_timer, jiffies + HZ);
1498c2ecf20Sopenharmony_ci		return;
1508c2ecf20Sopenharmony_ci	}
1518c2ecf20Sopenharmony_ci
1528c2ecf20Sopenharmony_ci	mr->mmkey.type = MLX5_MKEY_MR;
1538c2ecf20Sopenharmony_ci	mr->mmkey.key |= mlx5_idx_to_mkey(
1548c2ecf20Sopenharmony_ci		MLX5_GET(create_mkey_out, mr->out, mkey_index));
1558c2ecf20Sopenharmony_ci
1568c2ecf20Sopenharmony_ci	WRITE_ONCE(dev->cache.last_add, jiffies);
1578c2ecf20Sopenharmony_ci
1588c2ecf20Sopenharmony_ci	spin_lock_irqsave(&ent->lock, flags);
1598c2ecf20Sopenharmony_ci	list_add_tail(&mr->list, &ent->head);
1608c2ecf20Sopenharmony_ci	ent->available_mrs++;
1618c2ecf20Sopenharmony_ci	ent->total_mrs++;
1628c2ecf20Sopenharmony_ci	/* If we are doing fill_to_high_water then keep going. */
1638c2ecf20Sopenharmony_ci	queue_adjust_cache_locked(ent);
1648c2ecf20Sopenharmony_ci	ent->pending--;
1658c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&ent->lock, flags);
1668c2ecf20Sopenharmony_ci}
1678c2ecf20Sopenharmony_ci
1688c2ecf20Sopenharmony_cistatic struct mlx5_ib_mr *alloc_cache_mr(struct mlx5_cache_ent *ent, void *mkc)
1698c2ecf20Sopenharmony_ci{
1708c2ecf20Sopenharmony_ci	struct mlx5_ib_mr *mr;
1718c2ecf20Sopenharmony_ci
1728c2ecf20Sopenharmony_ci	mr = kzalloc(sizeof(*mr), GFP_KERNEL);
1738c2ecf20Sopenharmony_ci	if (!mr)
1748c2ecf20Sopenharmony_ci		return NULL;
1758c2ecf20Sopenharmony_ci	mr->order = ent->order;
1768c2ecf20Sopenharmony_ci	mr->cache_ent = ent;
1778c2ecf20Sopenharmony_ci	mr->dev = ent->dev;
1788c2ecf20Sopenharmony_ci
1798c2ecf20Sopenharmony_ci	set_mkc_access_pd_addr_fields(mkc, 0, 0, ent->dev->umrc.pd);
1808c2ecf20Sopenharmony_ci	MLX5_SET(mkc, mkc, free, 1);
1818c2ecf20Sopenharmony_ci	MLX5_SET(mkc, mkc, umr_en, 1);
1828c2ecf20Sopenharmony_ci	MLX5_SET(mkc, mkc, access_mode_1_0, ent->access_mode & 0x3);
1838c2ecf20Sopenharmony_ci	MLX5_SET(mkc, mkc, access_mode_4_2, (ent->access_mode >> 2) & 0x7);
1848c2ecf20Sopenharmony_ci
1858c2ecf20Sopenharmony_ci	MLX5_SET(mkc, mkc, translations_octword_size, ent->xlt);
1868c2ecf20Sopenharmony_ci	MLX5_SET(mkc, mkc, log_page_size, ent->page);
1878c2ecf20Sopenharmony_ci	return mr;
1888c2ecf20Sopenharmony_ci}
1898c2ecf20Sopenharmony_ci
1908c2ecf20Sopenharmony_ci/* Asynchronously schedule new MRs to be populated in the cache. */
1918c2ecf20Sopenharmony_cistatic int add_keys(struct mlx5_cache_ent *ent, unsigned int num)
1928c2ecf20Sopenharmony_ci{
1938c2ecf20Sopenharmony_ci	size_t inlen = MLX5_ST_SZ_BYTES(create_mkey_in);
1948c2ecf20Sopenharmony_ci	struct mlx5_ib_mr *mr;
1958c2ecf20Sopenharmony_ci	void *mkc;
1968c2ecf20Sopenharmony_ci	u32 *in;
1978c2ecf20Sopenharmony_ci	int err = 0;
1988c2ecf20Sopenharmony_ci	int i;
1998c2ecf20Sopenharmony_ci
2008c2ecf20Sopenharmony_ci	in = kzalloc(inlen, GFP_KERNEL);
2018c2ecf20Sopenharmony_ci	if (!in)
2028c2ecf20Sopenharmony_ci		return -ENOMEM;
2038c2ecf20Sopenharmony_ci
2048c2ecf20Sopenharmony_ci	mkc = MLX5_ADDR_OF(create_mkey_in, in, memory_key_mkey_entry);
2058c2ecf20Sopenharmony_ci	for (i = 0; i < num; i++) {
2068c2ecf20Sopenharmony_ci		mr = alloc_cache_mr(ent, mkc);
2078c2ecf20Sopenharmony_ci		if (!mr) {
2088c2ecf20Sopenharmony_ci			err = -ENOMEM;
2098c2ecf20Sopenharmony_ci			break;
2108c2ecf20Sopenharmony_ci		}
2118c2ecf20Sopenharmony_ci		spin_lock_irq(&ent->lock);
2128c2ecf20Sopenharmony_ci		if (ent->pending >= MAX_PENDING_REG_MR) {
2138c2ecf20Sopenharmony_ci			err = -EAGAIN;
2148c2ecf20Sopenharmony_ci			spin_unlock_irq(&ent->lock);
2158c2ecf20Sopenharmony_ci			kfree(mr);
2168c2ecf20Sopenharmony_ci			break;
2178c2ecf20Sopenharmony_ci		}
2188c2ecf20Sopenharmony_ci		ent->pending++;
2198c2ecf20Sopenharmony_ci		spin_unlock_irq(&ent->lock);
2208c2ecf20Sopenharmony_ci		err = mlx5_ib_create_mkey_cb(ent->dev, &mr->mmkey,
2218c2ecf20Sopenharmony_ci					     &ent->dev->async_ctx, in, inlen,
2228c2ecf20Sopenharmony_ci					     mr->out, sizeof(mr->out),
2238c2ecf20Sopenharmony_ci					     &mr->cb_work);
2248c2ecf20Sopenharmony_ci		if (err) {
2258c2ecf20Sopenharmony_ci			spin_lock_irq(&ent->lock);
2268c2ecf20Sopenharmony_ci			ent->pending--;
2278c2ecf20Sopenharmony_ci			spin_unlock_irq(&ent->lock);
2288c2ecf20Sopenharmony_ci			mlx5_ib_warn(ent->dev, "create mkey failed %d\n", err);
2298c2ecf20Sopenharmony_ci			kfree(mr);
2308c2ecf20Sopenharmony_ci			break;
2318c2ecf20Sopenharmony_ci		}
2328c2ecf20Sopenharmony_ci	}
2338c2ecf20Sopenharmony_ci
2348c2ecf20Sopenharmony_ci	kfree(in);
2358c2ecf20Sopenharmony_ci	return err;
2368c2ecf20Sopenharmony_ci}
2378c2ecf20Sopenharmony_ci
2388c2ecf20Sopenharmony_ci/* Synchronously create a MR in the cache */
2398c2ecf20Sopenharmony_cistatic struct mlx5_ib_mr *create_cache_mr(struct mlx5_cache_ent *ent)
2408c2ecf20Sopenharmony_ci{
2418c2ecf20Sopenharmony_ci	size_t inlen = MLX5_ST_SZ_BYTES(create_mkey_in);
2428c2ecf20Sopenharmony_ci	struct mlx5_ib_mr *mr;
2438c2ecf20Sopenharmony_ci	void *mkc;
2448c2ecf20Sopenharmony_ci	u32 *in;
2458c2ecf20Sopenharmony_ci	int err;
2468c2ecf20Sopenharmony_ci
2478c2ecf20Sopenharmony_ci	in = kzalloc(inlen, GFP_KERNEL);
2488c2ecf20Sopenharmony_ci	if (!in)
2498c2ecf20Sopenharmony_ci		return ERR_PTR(-ENOMEM);
2508c2ecf20Sopenharmony_ci	mkc = MLX5_ADDR_OF(create_mkey_in, in, memory_key_mkey_entry);
2518c2ecf20Sopenharmony_ci
2528c2ecf20Sopenharmony_ci	mr = alloc_cache_mr(ent, mkc);
2538c2ecf20Sopenharmony_ci	if (!mr) {
2548c2ecf20Sopenharmony_ci		err = -ENOMEM;
2558c2ecf20Sopenharmony_ci		goto free_in;
2568c2ecf20Sopenharmony_ci	}
2578c2ecf20Sopenharmony_ci
2588c2ecf20Sopenharmony_ci	err = mlx5_core_create_mkey(ent->dev->mdev, &mr->mmkey, in, inlen);
2598c2ecf20Sopenharmony_ci	if (err)
2608c2ecf20Sopenharmony_ci		goto free_mr;
2618c2ecf20Sopenharmony_ci
2628c2ecf20Sopenharmony_ci	mr->mmkey.type = MLX5_MKEY_MR;
2638c2ecf20Sopenharmony_ci	WRITE_ONCE(ent->dev->cache.last_add, jiffies);
2648c2ecf20Sopenharmony_ci	spin_lock_irq(&ent->lock);
2658c2ecf20Sopenharmony_ci	ent->total_mrs++;
2668c2ecf20Sopenharmony_ci	spin_unlock_irq(&ent->lock);
2678c2ecf20Sopenharmony_ci	kfree(in);
2688c2ecf20Sopenharmony_ci	return mr;
2698c2ecf20Sopenharmony_cifree_mr:
2708c2ecf20Sopenharmony_ci	kfree(mr);
2718c2ecf20Sopenharmony_cifree_in:
2728c2ecf20Sopenharmony_ci	kfree(in);
2738c2ecf20Sopenharmony_ci	return ERR_PTR(err);
2748c2ecf20Sopenharmony_ci}
2758c2ecf20Sopenharmony_ci
2768c2ecf20Sopenharmony_cistatic void remove_cache_mr_locked(struct mlx5_cache_ent *ent)
2778c2ecf20Sopenharmony_ci{
2788c2ecf20Sopenharmony_ci	struct mlx5_ib_mr *mr;
2798c2ecf20Sopenharmony_ci
2808c2ecf20Sopenharmony_ci	lockdep_assert_held(&ent->lock);
2818c2ecf20Sopenharmony_ci	if (list_empty(&ent->head))
2828c2ecf20Sopenharmony_ci		return;
2838c2ecf20Sopenharmony_ci	mr = list_first_entry(&ent->head, struct mlx5_ib_mr, list);
2848c2ecf20Sopenharmony_ci	list_del(&mr->list);
2858c2ecf20Sopenharmony_ci	ent->available_mrs--;
2868c2ecf20Sopenharmony_ci	ent->total_mrs--;
2878c2ecf20Sopenharmony_ci	spin_unlock_irq(&ent->lock);
2888c2ecf20Sopenharmony_ci	mlx5_core_destroy_mkey(ent->dev->mdev, &mr->mmkey);
2898c2ecf20Sopenharmony_ci	kfree(mr);
2908c2ecf20Sopenharmony_ci	spin_lock_irq(&ent->lock);
2918c2ecf20Sopenharmony_ci}
2928c2ecf20Sopenharmony_ci
2938c2ecf20Sopenharmony_cistatic int resize_available_mrs(struct mlx5_cache_ent *ent, unsigned int target,
2948c2ecf20Sopenharmony_ci				bool limit_fill)
2958c2ecf20Sopenharmony_ci{
2968c2ecf20Sopenharmony_ci	int err;
2978c2ecf20Sopenharmony_ci
2988c2ecf20Sopenharmony_ci	lockdep_assert_held(&ent->lock);
2998c2ecf20Sopenharmony_ci
3008c2ecf20Sopenharmony_ci	while (true) {
3018c2ecf20Sopenharmony_ci		if (limit_fill)
3028c2ecf20Sopenharmony_ci			target = ent->limit * 2;
3038c2ecf20Sopenharmony_ci		if (target == ent->available_mrs + ent->pending)
3048c2ecf20Sopenharmony_ci			return 0;
3058c2ecf20Sopenharmony_ci		if (target > ent->available_mrs + ent->pending) {
3068c2ecf20Sopenharmony_ci			u32 todo = target - (ent->available_mrs + ent->pending);
3078c2ecf20Sopenharmony_ci
3088c2ecf20Sopenharmony_ci			spin_unlock_irq(&ent->lock);
3098c2ecf20Sopenharmony_ci			err = add_keys(ent, todo);
3108c2ecf20Sopenharmony_ci			if (err == -EAGAIN)
3118c2ecf20Sopenharmony_ci				usleep_range(3000, 5000);
3128c2ecf20Sopenharmony_ci			spin_lock_irq(&ent->lock);
3138c2ecf20Sopenharmony_ci			if (err) {
3148c2ecf20Sopenharmony_ci				if (err != -EAGAIN)
3158c2ecf20Sopenharmony_ci					return err;
3168c2ecf20Sopenharmony_ci			} else
3178c2ecf20Sopenharmony_ci				return 0;
3188c2ecf20Sopenharmony_ci		} else {
3198c2ecf20Sopenharmony_ci			remove_cache_mr_locked(ent);
3208c2ecf20Sopenharmony_ci		}
3218c2ecf20Sopenharmony_ci	}
3228c2ecf20Sopenharmony_ci}
3238c2ecf20Sopenharmony_ci
3248c2ecf20Sopenharmony_cistatic ssize_t size_write(struct file *filp, const char __user *buf,
3258c2ecf20Sopenharmony_ci			  size_t count, loff_t *pos)
3268c2ecf20Sopenharmony_ci{
3278c2ecf20Sopenharmony_ci	struct mlx5_cache_ent *ent = filp->private_data;
3288c2ecf20Sopenharmony_ci	u32 target;
3298c2ecf20Sopenharmony_ci	int err;
3308c2ecf20Sopenharmony_ci
3318c2ecf20Sopenharmony_ci	err = kstrtou32_from_user(buf, count, 0, &target);
3328c2ecf20Sopenharmony_ci	if (err)
3338c2ecf20Sopenharmony_ci		return err;
3348c2ecf20Sopenharmony_ci
3358c2ecf20Sopenharmony_ci	/*
3368c2ecf20Sopenharmony_ci	 * Target is the new value of total_mrs the user requests, however we
3378c2ecf20Sopenharmony_ci	 * cannot free MRs that are in use. Compute the target value for
3388c2ecf20Sopenharmony_ci	 * available_mrs.
3398c2ecf20Sopenharmony_ci	 */
3408c2ecf20Sopenharmony_ci	spin_lock_irq(&ent->lock);
3418c2ecf20Sopenharmony_ci	if (target < ent->total_mrs - ent->available_mrs) {
3428c2ecf20Sopenharmony_ci		err = -EINVAL;
3438c2ecf20Sopenharmony_ci		goto err_unlock;
3448c2ecf20Sopenharmony_ci	}
3458c2ecf20Sopenharmony_ci	target = target - (ent->total_mrs - ent->available_mrs);
3468c2ecf20Sopenharmony_ci	if (target < ent->limit || target > ent->limit*2) {
3478c2ecf20Sopenharmony_ci		err = -EINVAL;
3488c2ecf20Sopenharmony_ci		goto err_unlock;
3498c2ecf20Sopenharmony_ci	}
3508c2ecf20Sopenharmony_ci	err = resize_available_mrs(ent, target, false);
3518c2ecf20Sopenharmony_ci	if (err)
3528c2ecf20Sopenharmony_ci		goto err_unlock;
3538c2ecf20Sopenharmony_ci	spin_unlock_irq(&ent->lock);
3548c2ecf20Sopenharmony_ci
3558c2ecf20Sopenharmony_ci	return count;
3568c2ecf20Sopenharmony_ci
3578c2ecf20Sopenharmony_cierr_unlock:
3588c2ecf20Sopenharmony_ci	spin_unlock_irq(&ent->lock);
3598c2ecf20Sopenharmony_ci	return err;
3608c2ecf20Sopenharmony_ci}
3618c2ecf20Sopenharmony_ci
3628c2ecf20Sopenharmony_cistatic ssize_t size_read(struct file *filp, char __user *buf, size_t count,
3638c2ecf20Sopenharmony_ci			 loff_t *pos)
3648c2ecf20Sopenharmony_ci{
3658c2ecf20Sopenharmony_ci	struct mlx5_cache_ent *ent = filp->private_data;
3668c2ecf20Sopenharmony_ci	char lbuf[20];
3678c2ecf20Sopenharmony_ci	int err;
3688c2ecf20Sopenharmony_ci
3698c2ecf20Sopenharmony_ci	err = snprintf(lbuf, sizeof(lbuf), "%d\n", ent->total_mrs);
3708c2ecf20Sopenharmony_ci	if (err < 0)
3718c2ecf20Sopenharmony_ci		return err;
3728c2ecf20Sopenharmony_ci
3738c2ecf20Sopenharmony_ci	return simple_read_from_buffer(buf, count, pos, lbuf, err);
3748c2ecf20Sopenharmony_ci}
3758c2ecf20Sopenharmony_ci
3768c2ecf20Sopenharmony_cistatic const struct file_operations size_fops = {
3778c2ecf20Sopenharmony_ci	.owner	= THIS_MODULE,
3788c2ecf20Sopenharmony_ci	.open	= simple_open,
3798c2ecf20Sopenharmony_ci	.write	= size_write,
3808c2ecf20Sopenharmony_ci	.read	= size_read,
3818c2ecf20Sopenharmony_ci};
3828c2ecf20Sopenharmony_ci
3838c2ecf20Sopenharmony_cistatic ssize_t limit_write(struct file *filp, const char __user *buf,
3848c2ecf20Sopenharmony_ci			   size_t count, loff_t *pos)
3858c2ecf20Sopenharmony_ci{
3868c2ecf20Sopenharmony_ci	struct mlx5_cache_ent *ent = filp->private_data;
3878c2ecf20Sopenharmony_ci	u32 var;
3888c2ecf20Sopenharmony_ci	int err;
3898c2ecf20Sopenharmony_ci
3908c2ecf20Sopenharmony_ci	err = kstrtou32_from_user(buf, count, 0, &var);
3918c2ecf20Sopenharmony_ci	if (err)
3928c2ecf20Sopenharmony_ci		return err;
3938c2ecf20Sopenharmony_ci
3948c2ecf20Sopenharmony_ci	/*
3958c2ecf20Sopenharmony_ci	 * Upon set we immediately fill the cache to high water mark implied by
3968c2ecf20Sopenharmony_ci	 * the limit.
3978c2ecf20Sopenharmony_ci	 */
3988c2ecf20Sopenharmony_ci	spin_lock_irq(&ent->lock);
3998c2ecf20Sopenharmony_ci	ent->limit = var;
4008c2ecf20Sopenharmony_ci	err = resize_available_mrs(ent, 0, true);
4018c2ecf20Sopenharmony_ci	spin_unlock_irq(&ent->lock);
4028c2ecf20Sopenharmony_ci	if (err)
4038c2ecf20Sopenharmony_ci		return err;
4048c2ecf20Sopenharmony_ci	return count;
4058c2ecf20Sopenharmony_ci}
4068c2ecf20Sopenharmony_ci
4078c2ecf20Sopenharmony_cistatic ssize_t limit_read(struct file *filp, char __user *buf, size_t count,
4088c2ecf20Sopenharmony_ci			  loff_t *pos)
4098c2ecf20Sopenharmony_ci{
4108c2ecf20Sopenharmony_ci	struct mlx5_cache_ent *ent = filp->private_data;
4118c2ecf20Sopenharmony_ci	char lbuf[20];
4128c2ecf20Sopenharmony_ci	int err;
4138c2ecf20Sopenharmony_ci
4148c2ecf20Sopenharmony_ci	err = snprintf(lbuf, sizeof(lbuf), "%d\n", ent->limit);
4158c2ecf20Sopenharmony_ci	if (err < 0)
4168c2ecf20Sopenharmony_ci		return err;
4178c2ecf20Sopenharmony_ci
4188c2ecf20Sopenharmony_ci	return simple_read_from_buffer(buf, count, pos, lbuf, err);
4198c2ecf20Sopenharmony_ci}
4208c2ecf20Sopenharmony_ci
4218c2ecf20Sopenharmony_cistatic const struct file_operations limit_fops = {
4228c2ecf20Sopenharmony_ci	.owner	= THIS_MODULE,
4238c2ecf20Sopenharmony_ci	.open	= simple_open,
4248c2ecf20Sopenharmony_ci	.write	= limit_write,
4258c2ecf20Sopenharmony_ci	.read	= limit_read,
4268c2ecf20Sopenharmony_ci};
4278c2ecf20Sopenharmony_ci
4288c2ecf20Sopenharmony_cistatic bool someone_adding(struct mlx5_mr_cache *cache)
4298c2ecf20Sopenharmony_ci{
4308c2ecf20Sopenharmony_ci	unsigned int i;
4318c2ecf20Sopenharmony_ci
4328c2ecf20Sopenharmony_ci	for (i = 0; i < MAX_MR_CACHE_ENTRIES; i++) {
4338c2ecf20Sopenharmony_ci		struct mlx5_cache_ent *ent = &cache->ent[i];
4348c2ecf20Sopenharmony_ci		bool ret;
4358c2ecf20Sopenharmony_ci
4368c2ecf20Sopenharmony_ci		spin_lock_irq(&ent->lock);
4378c2ecf20Sopenharmony_ci		ret = ent->available_mrs < ent->limit;
4388c2ecf20Sopenharmony_ci		spin_unlock_irq(&ent->lock);
4398c2ecf20Sopenharmony_ci		if (ret)
4408c2ecf20Sopenharmony_ci			return true;
4418c2ecf20Sopenharmony_ci	}
4428c2ecf20Sopenharmony_ci	return false;
4438c2ecf20Sopenharmony_ci}
4448c2ecf20Sopenharmony_ci
4458c2ecf20Sopenharmony_ci/*
4468c2ecf20Sopenharmony_ci * Check if the bucket is outside the high/low water mark and schedule an async
4478c2ecf20Sopenharmony_ci * update. The cache refill has hysteresis, once the low water mark is hit it is
4488c2ecf20Sopenharmony_ci * refilled up to the high mark.
4498c2ecf20Sopenharmony_ci */
4508c2ecf20Sopenharmony_cistatic void queue_adjust_cache_locked(struct mlx5_cache_ent *ent)
4518c2ecf20Sopenharmony_ci{
4528c2ecf20Sopenharmony_ci	lockdep_assert_held(&ent->lock);
4538c2ecf20Sopenharmony_ci
4548c2ecf20Sopenharmony_ci	if (ent->disabled || READ_ONCE(ent->dev->fill_delay))
4558c2ecf20Sopenharmony_ci		return;
4568c2ecf20Sopenharmony_ci	if (ent->available_mrs < ent->limit) {
4578c2ecf20Sopenharmony_ci		ent->fill_to_high_water = true;
4588c2ecf20Sopenharmony_ci		queue_work(ent->dev->cache.wq, &ent->work);
4598c2ecf20Sopenharmony_ci	} else if (ent->fill_to_high_water &&
4608c2ecf20Sopenharmony_ci		   ent->available_mrs + ent->pending < 2 * ent->limit) {
4618c2ecf20Sopenharmony_ci		/*
4628c2ecf20Sopenharmony_ci		 * Once we start populating due to hitting a low water mark
4638c2ecf20Sopenharmony_ci		 * continue until we pass the high water mark.
4648c2ecf20Sopenharmony_ci		 */
4658c2ecf20Sopenharmony_ci		queue_work(ent->dev->cache.wq, &ent->work);
4668c2ecf20Sopenharmony_ci	} else if (ent->available_mrs == 2 * ent->limit) {
4678c2ecf20Sopenharmony_ci		ent->fill_to_high_water = false;
4688c2ecf20Sopenharmony_ci	} else if (ent->available_mrs > 2 * ent->limit) {
4698c2ecf20Sopenharmony_ci		/* Queue deletion of excess entries */
4708c2ecf20Sopenharmony_ci		ent->fill_to_high_water = false;
4718c2ecf20Sopenharmony_ci		if (ent->pending)
4728c2ecf20Sopenharmony_ci			queue_delayed_work(ent->dev->cache.wq, &ent->dwork,
4738c2ecf20Sopenharmony_ci					   msecs_to_jiffies(1000));
4748c2ecf20Sopenharmony_ci		else
4758c2ecf20Sopenharmony_ci			queue_work(ent->dev->cache.wq, &ent->work);
4768c2ecf20Sopenharmony_ci	}
4778c2ecf20Sopenharmony_ci}
4788c2ecf20Sopenharmony_ci
4798c2ecf20Sopenharmony_cistatic void __cache_work_func(struct mlx5_cache_ent *ent)
4808c2ecf20Sopenharmony_ci{
4818c2ecf20Sopenharmony_ci	struct mlx5_ib_dev *dev = ent->dev;
4828c2ecf20Sopenharmony_ci	struct mlx5_mr_cache *cache = &dev->cache;
4838c2ecf20Sopenharmony_ci	int err;
4848c2ecf20Sopenharmony_ci
4858c2ecf20Sopenharmony_ci	spin_lock_irq(&ent->lock);
4868c2ecf20Sopenharmony_ci	if (ent->disabled)
4878c2ecf20Sopenharmony_ci		goto out;
4888c2ecf20Sopenharmony_ci
4898c2ecf20Sopenharmony_ci	if (ent->fill_to_high_water &&
4908c2ecf20Sopenharmony_ci	    ent->available_mrs + ent->pending < 2 * ent->limit &&
4918c2ecf20Sopenharmony_ci	    !READ_ONCE(dev->fill_delay)) {
4928c2ecf20Sopenharmony_ci		spin_unlock_irq(&ent->lock);
4938c2ecf20Sopenharmony_ci		err = add_keys(ent, 1);
4948c2ecf20Sopenharmony_ci		spin_lock_irq(&ent->lock);
4958c2ecf20Sopenharmony_ci		if (ent->disabled)
4968c2ecf20Sopenharmony_ci			goto out;
4978c2ecf20Sopenharmony_ci		if (err) {
4988c2ecf20Sopenharmony_ci			/*
4998c2ecf20Sopenharmony_ci			 * EAGAIN only happens if pending is positive, so we
5008c2ecf20Sopenharmony_ci			 * will be rescheduled from reg_mr_callback(). The only
5018c2ecf20Sopenharmony_ci			 * failure path here is ENOMEM.
5028c2ecf20Sopenharmony_ci			 */
5038c2ecf20Sopenharmony_ci			if (err != -EAGAIN) {
5048c2ecf20Sopenharmony_ci				mlx5_ib_warn(
5058c2ecf20Sopenharmony_ci					dev,
5068c2ecf20Sopenharmony_ci					"command failed order %d, err %d\n",
5078c2ecf20Sopenharmony_ci					ent->order, err);
5088c2ecf20Sopenharmony_ci				queue_delayed_work(cache->wq, &ent->dwork,
5098c2ecf20Sopenharmony_ci						   msecs_to_jiffies(1000));
5108c2ecf20Sopenharmony_ci			}
5118c2ecf20Sopenharmony_ci		}
5128c2ecf20Sopenharmony_ci	} else if (ent->available_mrs > 2 * ent->limit) {
5138c2ecf20Sopenharmony_ci		bool need_delay;
5148c2ecf20Sopenharmony_ci
5158c2ecf20Sopenharmony_ci		/*
5168c2ecf20Sopenharmony_ci		 * The remove_cache_mr() logic is performed as garbage
5178c2ecf20Sopenharmony_ci		 * collection task. Such task is intended to be run when no
5188c2ecf20Sopenharmony_ci		 * other active processes are running.
5198c2ecf20Sopenharmony_ci		 *
5208c2ecf20Sopenharmony_ci		 * The need_resched() will return TRUE if there are user tasks
5218c2ecf20Sopenharmony_ci		 * to be activated in near future.
5228c2ecf20Sopenharmony_ci		 *
5238c2ecf20Sopenharmony_ci		 * In such case, we don't execute remove_cache_mr() and postpone
5248c2ecf20Sopenharmony_ci		 * the garbage collection work to try to run in next cycle, in
5258c2ecf20Sopenharmony_ci		 * order to free CPU resources to other tasks.
5268c2ecf20Sopenharmony_ci		 */
5278c2ecf20Sopenharmony_ci		spin_unlock_irq(&ent->lock);
5288c2ecf20Sopenharmony_ci		need_delay = need_resched() || someone_adding(cache) ||
5298c2ecf20Sopenharmony_ci			     !time_after(jiffies,
5308c2ecf20Sopenharmony_ci					 READ_ONCE(cache->last_add) + 300 * HZ);
5318c2ecf20Sopenharmony_ci		spin_lock_irq(&ent->lock);
5328c2ecf20Sopenharmony_ci		if (ent->disabled)
5338c2ecf20Sopenharmony_ci			goto out;
5348c2ecf20Sopenharmony_ci		if (need_delay) {
5358c2ecf20Sopenharmony_ci			queue_delayed_work(cache->wq, &ent->dwork, 300 * HZ);
5368c2ecf20Sopenharmony_ci			goto out;
5378c2ecf20Sopenharmony_ci		}
5388c2ecf20Sopenharmony_ci		remove_cache_mr_locked(ent);
5398c2ecf20Sopenharmony_ci		queue_adjust_cache_locked(ent);
5408c2ecf20Sopenharmony_ci	}
5418c2ecf20Sopenharmony_ciout:
5428c2ecf20Sopenharmony_ci	spin_unlock_irq(&ent->lock);
5438c2ecf20Sopenharmony_ci}
5448c2ecf20Sopenharmony_ci
5458c2ecf20Sopenharmony_cistatic void delayed_cache_work_func(struct work_struct *work)
5468c2ecf20Sopenharmony_ci{
5478c2ecf20Sopenharmony_ci	struct mlx5_cache_ent *ent;
5488c2ecf20Sopenharmony_ci
5498c2ecf20Sopenharmony_ci	ent = container_of(work, struct mlx5_cache_ent, dwork.work);
5508c2ecf20Sopenharmony_ci	__cache_work_func(ent);
5518c2ecf20Sopenharmony_ci}
5528c2ecf20Sopenharmony_ci
5538c2ecf20Sopenharmony_cistatic void cache_work_func(struct work_struct *work)
5548c2ecf20Sopenharmony_ci{
5558c2ecf20Sopenharmony_ci	struct mlx5_cache_ent *ent;
5568c2ecf20Sopenharmony_ci
5578c2ecf20Sopenharmony_ci	ent = container_of(work, struct mlx5_cache_ent, work);
5588c2ecf20Sopenharmony_ci	__cache_work_func(ent);
5598c2ecf20Sopenharmony_ci}
5608c2ecf20Sopenharmony_ci
5618c2ecf20Sopenharmony_ci/* Allocate a special entry from the cache */
5628c2ecf20Sopenharmony_cistruct mlx5_ib_mr *mlx5_mr_cache_alloc(struct mlx5_ib_dev *dev,
5638c2ecf20Sopenharmony_ci				       unsigned int entry, int access_flags)
5648c2ecf20Sopenharmony_ci{
5658c2ecf20Sopenharmony_ci	struct mlx5_mr_cache *cache = &dev->cache;
5668c2ecf20Sopenharmony_ci	struct mlx5_cache_ent *ent;
5678c2ecf20Sopenharmony_ci	struct mlx5_ib_mr *mr;
5688c2ecf20Sopenharmony_ci
5698c2ecf20Sopenharmony_ci	if (WARN_ON(entry <= MR_CACHE_LAST_STD_ENTRY ||
5708c2ecf20Sopenharmony_ci		    entry >= ARRAY_SIZE(cache->ent)))
5718c2ecf20Sopenharmony_ci		return ERR_PTR(-EINVAL);
5728c2ecf20Sopenharmony_ci
5738c2ecf20Sopenharmony_ci	/* Matches access in alloc_cache_mr() */
5748c2ecf20Sopenharmony_ci	if (!mlx5_ib_can_reconfig_with_umr(dev, 0, access_flags))
5758c2ecf20Sopenharmony_ci		return ERR_PTR(-EOPNOTSUPP);
5768c2ecf20Sopenharmony_ci
5778c2ecf20Sopenharmony_ci	ent = &cache->ent[entry];
5788c2ecf20Sopenharmony_ci	spin_lock_irq(&ent->lock);
5798c2ecf20Sopenharmony_ci	if (list_empty(&ent->head)) {
5808c2ecf20Sopenharmony_ci		queue_adjust_cache_locked(ent);
5818c2ecf20Sopenharmony_ci		ent->miss++;
5828c2ecf20Sopenharmony_ci		spin_unlock_irq(&ent->lock);
5838c2ecf20Sopenharmony_ci		mr = create_cache_mr(ent);
5848c2ecf20Sopenharmony_ci		if (IS_ERR(mr))
5858c2ecf20Sopenharmony_ci			return mr;
5868c2ecf20Sopenharmony_ci	} else {
5878c2ecf20Sopenharmony_ci		mr = list_first_entry(&ent->head, struct mlx5_ib_mr, list);
5888c2ecf20Sopenharmony_ci		list_del(&mr->list);
5898c2ecf20Sopenharmony_ci		ent->available_mrs--;
5908c2ecf20Sopenharmony_ci		queue_adjust_cache_locked(ent);
5918c2ecf20Sopenharmony_ci		spin_unlock_irq(&ent->lock);
5928c2ecf20Sopenharmony_ci	}
5938c2ecf20Sopenharmony_ci	mr->access_flags = access_flags;
5948c2ecf20Sopenharmony_ci	return mr;
5958c2ecf20Sopenharmony_ci}
5968c2ecf20Sopenharmony_ci
5978c2ecf20Sopenharmony_ci/* Return a MR already available in the cache */
5988c2ecf20Sopenharmony_cistatic struct mlx5_ib_mr *get_cache_mr(struct mlx5_cache_ent *req_ent)
5998c2ecf20Sopenharmony_ci{
6008c2ecf20Sopenharmony_ci	struct mlx5_ib_dev *dev = req_ent->dev;
6018c2ecf20Sopenharmony_ci	struct mlx5_ib_mr *mr = NULL;
6028c2ecf20Sopenharmony_ci	struct mlx5_cache_ent *ent = req_ent;
6038c2ecf20Sopenharmony_ci
6048c2ecf20Sopenharmony_ci	/* Try larger MR pools from the cache to satisfy the allocation */
6058c2ecf20Sopenharmony_ci	for (; ent != &dev->cache.ent[MR_CACHE_LAST_STD_ENTRY + 1]; ent++) {
6068c2ecf20Sopenharmony_ci		mlx5_ib_dbg(dev, "order %u, cache index %zu\n", ent->order,
6078c2ecf20Sopenharmony_ci			    ent - dev->cache.ent);
6088c2ecf20Sopenharmony_ci
6098c2ecf20Sopenharmony_ci		spin_lock_irq(&ent->lock);
6108c2ecf20Sopenharmony_ci		if (!list_empty(&ent->head)) {
6118c2ecf20Sopenharmony_ci			mr = list_first_entry(&ent->head, struct mlx5_ib_mr,
6128c2ecf20Sopenharmony_ci					      list);
6138c2ecf20Sopenharmony_ci			list_del(&mr->list);
6148c2ecf20Sopenharmony_ci			ent->available_mrs--;
6158c2ecf20Sopenharmony_ci			queue_adjust_cache_locked(ent);
6168c2ecf20Sopenharmony_ci			spin_unlock_irq(&ent->lock);
6178c2ecf20Sopenharmony_ci			break;
6188c2ecf20Sopenharmony_ci		}
6198c2ecf20Sopenharmony_ci		queue_adjust_cache_locked(ent);
6208c2ecf20Sopenharmony_ci		spin_unlock_irq(&ent->lock);
6218c2ecf20Sopenharmony_ci	}
6228c2ecf20Sopenharmony_ci
6238c2ecf20Sopenharmony_ci	if (!mr)
6248c2ecf20Sopenharmony_ci		req_ent->miss++;
6258c2ecf20Sopenharmony_ci
6268c2ecf20Sopenharmony_ci	return mr;
6278c2ecf20Sopenharmony_ci}
6288c2ecf20Sopenharmony_ci
6298c2ecf20Sopenharmony_cistatic void detach_mr_from_cache(struct mlx5_ib_mr *mr)
6308c2ecf20Sopenharmony_ci{
6318c2ecf20Sopenharmony_ci	struct mlx5_cache_ent *ent = mr->cache_ent;
6328c2ecf20Sopenharmony_ci
6338c2ecf20Sopenharmony_ci	mr->cache_ent = NULL;
6348c2ecf20Sopenharmony_ci	spin_lock_irq(&ent->lock);
6358c2ecf20Sopenharmony_ci	ent->total_mrs--;
6368c2ecf20Sopenharmony_ci	spin_unlock_irq(&ent->lock);
6378c2ecf20Sopenharmony_ci}
6388c2ecf20Sopenharmony_ci
6398c2ecf20Sopenharmony_civoid mlx5_mr_cache_free(struct mlx5_ib_dev *dev, struct mlx5_ib_mr *mr)
6408c2ecf20Sopenharmony_ci{
6418c2ecf20Sopenharmony_ci	struct mlx5_cache_ent *ent = mr->cache_ent;
6428c2ecf20Sopenharmony_ci
6438c2ecf20Sopenharmony_ci	if (!ent)
6448c2ecf20Sopenharmony_ci		return;
6458c2ecf20Sopenharmony_ci
6468c2ecf20Sopenharmony_ci	if (mlx5_mr_cache_invalidate(mr)) {
6478c2ecf20Sopenharmony_ci		detach_mr_from_cache(mr);
6488c2ecf20Sopenharmony_ci		destroy_mkey(dev, mr);
6498c2ecf20Sopenharmony_ci		kfree(mr);
6508c2ecf20Sopenharmony_ci		return;
6518c2ecf20Sopenharmony_ci	}
6528c2ecf20Sopenharmony_ci
6538c2ecf20Sopenharmony_ci	spin_lock_irq(&ent->lock);
6548c2ecf20Sopenharmony_ci	list_add_tail(&mr->list, &ent->head);
6558c2ecf20Sopenharmony_ci	ent->available_mrs++;
6568c2ecf20Sopenharmony_ci	queue_adjust_cache_locked(ent);
6578c2ecf20Sopenharmony_ci	spin_unlock_irq(&ent->lock);
6588c2ecf20Sopenharmony_ci}
6598c2ecf20Sopenharmony_ci
6608c2ecf20Sopenharmony_cistatic void clean_keys(struct mlx5_ib_dev *dev, int c)
6618c2ecf20Sopenharmony_ci{
6628c2ecf20Sopenharmony_ci	struct mlx5_mr_cache *cache = &dev->cache;
6638c2ecf20Sopenharmony_ci	struct mlx5_cache_ent *ent = &cache->ent[c];
6648c2ecf20Sopenharmony_ci	struct mlx5_ib_mr *tmp_mr;
6658c2ecf20Sopenharmony_ci	struct mlx5_ib_mr *mr;
6668c2ecf20Sopenharmony_ci	LIST_HEAD(del_list);
6678c2ecf20Sopenharmony_ci
6688c2ecf20Sopenharmony_ci	cancel_delayed_work(&ent->dwork);
6698c2ecf20Sopenharmony_ci	while (1) {
6708c2ecf20Sopenharmony_ci		spin_lock_irq(&ent->lock);
6718c2ecf20Sopenharmony_ci		if (list_empty(&ent->head)) {
6728c2ecf20Sopenharmony_ci			spin_unlock_irq(&ent->lock);
6738c2ecf20Sopenharmony_ci			break;
6748c2ecf20Sopenharmony_ci		}
6758c2ecf20Sopenharmony_ci		mr = list_first_entry(&ent->head, struct mlx5_ib_mr, list);
6768c2ecf20Sopenharmony_ci		list_move(&mr->list, &del_list);
6778c2ecf20Sopenharmony_ci		ent->available_mrs--;
6788c2ecf20Sopenharmony_ci		ent->total_mrs--;
6798c2ecf20Sopenharmony_ci		spin_unlock_irq(&ent->lock);
6808c2ecf20Sopenharmony_ci		mlx5_core_destroy_mkey(dev->mdev, &mr->mmkey);
6818c2ecf20Sopenharmony_ci	}
6828c2ecf20Sopenharmony_ci
6838c2ecf20Sopenharmony_ci	list_for_each_entry_safe(mr, tmp_mr, &del_list, list) {
6848c2ecf20Sopenharmony_ci		list_del(&mr->list);
6858c2ecf20Sopenharmony_ci		kfree(mr);
6868c2ecf20Sopenharmony_ci	}
6878c2ecf20Sopenharmony_ci}
6888c2ecf20Sopenharmony_ci
6898c2ecf20Sopenharmony_cistatic void mlx5_mr_cache_debugfs_cleanup(struct mlx5_ib_dev *dev)
6908c2ecf20Sopenharmony_ci{
6918c2ecf20Sopenharmony_ci	if (!mlx5_debugfs_root || dev->is_rep)
6928c2ecf20Sopenharmony_ci		return;
6938c2ecf20Sopenharmony_ci
6948c2ecf20Sopenharmony_ci	debugfs_remove_recursive(dev->cache.root);
6958c2ecf20Sopenharmony_ci	dev->cache.root = NULL;
6968c2ecf20Sopenharmony_ci}
6978c2ecf20Sopenharmony_ci
6988c2ecf20Sopenharmony_cistatic void mlx5_mr_cache_debugfs_init(struct mlx5_ib_dev *dev)
6998c2ecf20Sopenharmony_ci{
7008c2ecf20Sopenharmony_ci	struct mlx5_mr_cache *cache = &dev->cache;
7018c2ecf20Sopenharmony_ci	struct mlx5_cache_ent *ent;
7028c2ecf20Sopenharmony_ci	struct dentry *dir;
7038c2ecf20Sopenharmony_ci	int i;
7048c2ecf20Sopenharmony_ci
7058c2ecf20Sopenharmony_ci	if (!mlx5_debugfs_root || dev->is_rep)
7068c2ecf20Sopenharmony_ci		return;
7078c2ecf20Sopenharmony_ci
7088c2ecf20Sopenharmony_ci	cache->root = debugfs_create_dir("mr_cache", dev->mdev->priv.dbg_root);
7098c2ecf20Sopenharmony_ci
7108c2ecf20Sopenharmony_ci	for (i = 0; i < MAX_MR_CACHE_ENTRIES; i++) {
7118c2ecf20Sopenharmony_ci		ent = &cache->ent[i];
7128c2ecf20Sopenharmony_ci		sprintf(ent->name, "%d", ent->order);
7138c2ecf20Sopenharmony_ci		dir = debugfs_create_dir(ent->name, cache->root);
7148c2ecf20Sopenharmony_ci		debugfs_create_file("size", 0600, dir, ent, &size_fops);
7158c2ecf20Sopenharmony_ci		debugfs_create_file("limit", 0600, dir, ent, &limit_fops);
7168c2ecf20Sopenharmony_ci		debugfs_create_u32("cur", 0400, dir, &ent->available_mrs);
7178c2ecf20Sopenharmony_ci		debugfs_create_u32("miss", 0600, dir, &ent->miss);
7188c2ecf20Sopenharmony_ci	}
7198c2ecf20Sopenharmony_ci}
7208c2ecf20Sopenharmony_ci
7218c2ecf20Sopenharmony_cistatic void delay_time_func(struct timer_list *t)
7228c2ecf20Sopenharmony_ci{
7238c2ecf20Sopenharmony_ci	struct mlx5_ib_dev *dev = from_timer(dev, t, delay_timer);
7248c2ecf20Sopenharmony_ci
7258c2ecf20Sopenharmony_ci	WRITE_ONCE(dev->fill_delay, 0);
7268c2ecf20Sopenharmony_ci}
7278c2ecf20Sopenharmony_ci
7288c2ecf20Sopenharmony_ciint mlx5_mr_cache_init(struct mlx5_ib_dev *dev)
7298c2ecf20Sopenharmony_ci{
7308c2ecf20Sopenharmony_ci	struct mlx5_mr_cache *cache = &dev->cache;
7318c2ecf20Sopenharmony_ci	struct mlx5_cache_ent *ent;
7328c2ecf20Sopenharmony_ci	int i;
7338c2ecf20Sopenharmony_ci
7348c2ecf20Sopenharmony_ci	mutex_init(&dev->slow_path_mutex);
7358c2ecf20Sopenharmony_ci	cache->wq = alloc_ordered_workqueue("mkey_cache", WQ_MEM_RECLAIM);
7368c2ecf20Sopenharmony_ci	if (!cache->wq) {
7378c2ecf20Sopenharmony_ci		mlx5_ib_warn(dev, "failed to create work queue\n");
7388c2ecf20Sopenharmony_ci		return -ENOMEM;
7398c2ecf20Sopenharmony_ci	}
7408c2ecf20Sopenharmony_ci
7418c2ecf20Sopenharmony_ci	mlx5_cmd_init_async_ctx(dev->mdev, &dev->async_ctx);
7428c2ecf20Sopenharmony_ci	timer_setup(&dev->delay_timer, delay_time_func, 0);
7438c2ecf20Sopenharmony_ci	for (i = 0; i < MAX_MR_CACHE_ENTRIES; i++) {
7448c2ecf20Sopenharmony_ci		ent = &cache->ent[i];
7458c2ecf20Sopenharmony_ci		INIT_LIST_HEAD(&ent->head);
7468c2ecf20Sopenharmony_ci		spin_lock_init(&ent->lock);
7478c2ecf20Sopenharmony_ci		ent->order = i + 2;
7488c2ecf20Sopenharmony_ci		ent->dev = dev;
7498c2ecf20Sopenharmony_ci		ent->limit = 0;
7508c2ecf20Sopenharmony_ci
7518c2ecf20Sopenharmony_ci		INIT_WORK(&ent->work, cache_work_func);
7528c2ecf20Sopenharmony_ci		INIT_DELAYED_WORK(&ent->dwork, delayed_cache_work_func);
7538c2ecf20Sopenharmony_ci
7548c2ecf20Sopenharmony_ci		if (i > MR_CACHE_LAST_STD_ENTRY) {
7558c2ecf20Sopenharmony_ci			mlx5_odp_init_mr_cache_entry(ent);
7568c2ecf20Sopenharmony_ci			continue;
7578c2ecf20Sopenharmony_ci		}
7588c2ecf20Sopenharmony_ci
7598c2ecf20Sopenharmony_ci		if (ent->order > mr_cache_max_order(dev))
7608c2ecf20Sopenharmony_ci			continue;
7618c2ecf20Sopenharmony_ci
7628c2ecf20Sopenharmony_ci		ent->page = PAGE_SHIFT;
7638c2ecf20Sopenharmony_ci		ent->xlt = (1 << ent->order) * sizeof(struct mlx5_mtt) /
7648c2ecf20Sopenharmony_ci			   MLX5_IB_UMR_OCTOWORD;
7658c2ecf20Sopenharmony_ci		ent->access_mode = MLX5_MKC_ACCESS_MODE_MTT;
7668c2ecf20Sopenharmony_ci		if ((dev->mdev->profile->mask & MLX5_PROF_MASK_MR_CACHE) &&
7678c2ecf20Sopenharmony_ci		    !dev->is_rep && mlx5_core_is_pf(dev->mdev) &&
7688c2ecf20Sopenharmony_ci		    mlx5_ib_can_load_pas_with_umr(dev, 0))
7698c2ecf20Sopenharmony_ci			ent->limit = dev->mdev->profile->mr_cache[i].limit;
7708c2ecf20Sopenharmony_ci		else
7718c2ecf20Sopenharmony_ci			ent->limit = 0;
7728c2ecf20Sopenharmony_ci		spin_lock_irq(&ent->lock);
7738c2ecf20Sopenharmony_ci		queue_adjust_cache_locked(ent);
7748c2ecf20Sopenharmony_ci		spin_unlock_irq(&ent->lock);
7758c2ecf20Sopenharmony_ci	}
7768c2ecf20Sopenharmony_ci
7778c2ecf20Sopenharmony_ci	mlx5_mr_cache_debugfs_init(dev);
7788c2ecf20Sopenharmony_ci
7798c2ecf20Sopenharmony_ci	return 0;
7808c2ecf20Sopenharmony_ci}
7818c2ecf20Sopenharmony_ci
7828c2ecf20Sopenharmony_ciint mlx5_mr_cache_cleanup(struct mlx5_ib_dev *dev)
7838c2ecf20Sopenharmony_ci{
7848c2ecf20Sopenharmony_ci	unsigned int i;
7858c2ecf20Sopenharmony_ci
7868c2ecf20Sopenharmony_ci	if (!dev->cache.wq)
7878c2ecf20Sopenharmony_ci		return 0;
7888c2ecf20Sopenharmony_ci
7898c2ecf20Sopenharmony_ci	for (i = 0; i < MAX_MR_CACHE_ENTRIES; i++) {
7908c2ecf20Sopenharmony_ci		struct mlx5_cache_ent *ent = &dev->cache.ent[i];
7918c2ecf20Sopenharmony_ci
7928c2ecf20Sopenharmony_ci		spin_lock_irq(&ent->lock);
7938c2ecf20Sopenharmony_ci		ent->disabled = true;
7948c2ecf20Sopenharmony_ci		spin_unlock_irq(&ent->lock);
7958c2ecf20Sopenharmony_ci		cancel_work_sync(&ent->work);
7968c2ecf20Sopenharmony_ci		cancel_delayed_work_sync(&ent->dwork);
7978c2ecf20Sopenharmony_ci	}
7988c2ecf20Sopenharmony_ci
7998c2ecf20Sopenharmony_ci	mlx5_mr_cache_debugfs_cleanup(dev);
8008c2ecf20Sopenharmony_ci	mlx5_cmd_cleanup_async_ctx(&dev->async_ctx);
8018c2ecf20Sopenharmony_ci
8028c2ecf20Sopenharmony_ci	for (i = 0; i < MAX_MR_CACHE_ENTRIES; i++)
8038c2ecf20Sopenharmony_ci		clean_keys(dev, i);
8048c2ecf20Sopenharmony_ci
8058c2ecf20Sopenharmony_ci	destroy_workqueue(dev->cache.wq);
8068c2ecf20Sopenharmony_ci	del_timer_sync(&dev->delay_timer);
8078c2ecf20Sopenharmony_ci
8088c2ecf20Sopenharmony_ci	return 0;
8098c2ecf20Sopenharmony_ci}
8108c2ecf20Sopenharmony_ci
8118c2ecf20Sopenharmony_cistruct ib_mr *mlx5_ib_get_dma_mr(struct ib_pd *pd, int acc)
8128c2ecf20Sopenharmony_ci{
8138c2ecf20Sopenharmony_ci	struct mlx5_ib_dev *dev = to_mdev(pd->device);
8148c2ecf20Sopenharmony_ci	int inlen = MLX5_ST_SZ_BYTES(create_mkey_in);
8158c2ecf20Sopenharmony_ci	struct mlx5_ib_mr *mr;
8168c2ecf20Sopenharmony_ci	void *mkc;
8178c2ecf20Sopenharmony_ci	u32 *in;
8188c2ecf20Sopenharmony_ci	int err;
8198c2ecf20Sopenharmony_ci
8208c2ecf20Sopenharmony_ci	mr = kzalloc(sizeof(*mr), GFP_KERNEL);
8218c2ecf20Sopenharmony_ci	if (!mr)
8228c2ecf20Sopenharmony_ci		return ERR_PTR(-ENOMEM);
8238c2ecf20Sopenharmony_ci
8248c2ecf20Sopenharmony_ci	in = kzalloc(inlen, GFP_KERNEL);
8258c2ecf20Sopenharmony_ci	if (!in) {
8268c2ecf20Sopenharmony_ci		err = -ENOMEM;
8278c2ecf20Sopenharmony_ci		goto err_free;
8288c2ecf20Sopenharmony_ci	}
8298c2ecf20Sopenharmony_ci
8308c2ecf20Sopenharmony_ci	mkc = MLX5_ADDR_OF(create_mkey_in, in, memory_key_mkey_entry);
8318c2ecf20Sopenharmony_ci
8328c2ecf20Sopenharmony_ci	MLX5_SET(mkc, mkc, access_mode_1_0, MLX5_MKC_ACCESS_MODE_PA);
8338c2ecf20Sopenharmony_ci	MLX5_SET(mkc, mkc, length64, 1);
8348c2ecf20Sopenharmony_ci	set_mkc_access_pd_addr_fields(mkc, acc, 0, pd);
8358c2ecf20Sopenharmony_ci
8368c2ecf20Sopenharmony_ci	err = mlx5_ib_create_mkey(dev, &mr->mmkey, in, inlen);
8378c2ecf20Sopenharmony_ci	if (err)
8388c2ecf20Sopenharmony_ci		goto err_in;
8398c2ecf20Sopenharmony_ci
8408c2ecf20Sopenharmony_ci	kfree(in);
8418c2ecf20Sopenharmony_ci	mr->mmkey.type = MLX5_MKEY_MR;
8428c2ecf20Sopenharmony_ci	mr->ibmr.lkey = mr->mmkey.key;
8438c2ecf20Sopenharmony_ci	mr->ibmr.rkey = mr->mmkey.key;
8448c2ecf20Sopenharmony_ci	mr->umem = NULL;
8458c2ecf20Sopenharmony_ci
8468c2ecf20Sopenharmony_ci	return &mr->ibmr;
8478c2ecf20Sopenharmony_ci
8488c2ecf20Sopenharmony_cierr_in:
8498c2ecf20Sopenharmony_ci	kfree(in);
8508c2ecf20Sopenharmony_ci
8518c2ecf20Sopenharmony_cierr_free:
8528c2ecf20Sopenharmony_ci	kfree(mr);
8538c2ecf20Sopenharmony_ci
8548c2ecf20Sopenharmony_ci	return ERR_PTR(err);
8558c2ecf20Sopenharmony_ci}
8568c2ecf20Sopenharmony_ci
8578c2ecf20Sopenharmony_cistatic int get_octo_len(u64 addr, u64 len, int page_shift)
8588c2ecf20Sopenharmony_ci{
8598c2ecf20Sopenharmony_ci	u64 page_size = 1ULL << page_shift;
8608c2ecf20Sopenharmony_ci	u64 offset;
8618c2ecf20Sopenharmony_ci	int npages;
8628c2ecf20Sopenharmony_ci
8638c2ecf20Sopenharmony_ci	offset = addr & (page_size - 1);
8648c2ecf20Sopenharmony_ci	npages = ALIGN(len + offset, page_size) >> page_shift;
8658c2ecf20Sopenharmony_ci	return (npages + 1) / 2;
8668c2ecf20Sopenharmony_ci}
8678c2ecf20Sopenharmony_ci
8688c2ecf20Sopenharmony_cistatic int mr_cache_max_order(struct mlx5_ib_dev *dev)
8698c2ecf20Sopenharmony_ci{
8708c2ecf20Sopenharmony_ci	if (MLX5_CAP_GEN(dev->mdev, umr_extended_translation_offset))
8718c2ecf20Sopenharmony_ci		return MR_CACHE_LAST_STD_ENTRY + 2;
8728c2ecf20Sopenharmony_ci	return MLX5_MAX_UMR_SHIFT;
8738c2ecf20Sopenharmony_ci}
8748c2ecf20Sopenharmony_ci
8758c2ecf20Sopenharmony_cistatic int mr_umem_get(struct mlx5_ib_dev *dev, u64 start, u64 length,
8768c2ecf20Sopenharmony_ci		       int access_flags, struct ib_umem **umem, int *npages,
8778c2ecf20Sopenharmony_ci		       int *page_shift, int *ncont, int *order)
8788c2ecf20Sopenharmony_ci{
8798c2ecf20Sopenharmony_ci	struct ib_umem *u;
8808c2ecf20Sopenharmony_ci
8818c2ecf20Sopenharmony_ci	*umem = NULL;
8828c2ecf20Sopenharmony_ci
8838c2ecf20Sopenharmony_ci	if (access_flags & IB_ACCESS_ON_DEMAND) {
8848c2ecf20Sopenharmony_ci		struct ib_umem_odp *odp;
8858c2ecf20Sopenharmony_ci
8868c2ecf20Sopenharmony_ci		odp = ib_umem_odp_get(&dev->ib_dev, start, length, access_flags,
8878c2ecf20Sopenharmony_ci				      &mlx5_mn_ops);
8888c2ecf20Sopenharmony_ci		if (IS_ERR(odp)) {
8898c2ecf20Sopenharmony_ci			mlx5_ib_dbg(dev, "umem get failed (%ld)\n",
8908c2ecf20Sopenharmony_ci				    PTR_ERR(odp));
8918c2ecf20Sopenharmony_ci			return PTR_ERR(odp);
8928c2ecf20Sopenharmony_ci		}
8938c2ecf20Sopenharmony_ci
8948c2ecf20Sopenharmony_ci		u = &odp->umem;
8958c2ecf20Sopenharmony_ci
8968c2ecf20Sopenharmony_ci		*page_shift = odp->page_shift;
8978c2ecf20Sopenharmony_ci		*ncont = ib_umem_odp_num_pages(odp);
8988c2ecf20Sopenharmony_ci		*npages = *ncont << (*page_shift - PAGE_SHIFT);
8998c2ecf20Sopenharmony_ci		if (order)
9008c2ecf20Sopenharmony_ci			*order = ilog2(roundup_pow_of_two(*ncont));
9018c2ecf20Sopenharmony_ci	} else {
9028c2ecf20Sopenharmony_ci		u = ib_umem_get(&dev->ib_dev, start, length, access_flags);
9038c2ecf20Sopenharmony_ci		if (IS_ERR(u)) {
9048c2ecf20Sopenharmony_ci			mlx5_ib_dbg(dev, "umem get failed (%ld)\n", PTR_ERR(u));
9058c2ecf20Sopenharmony_ci			return PTR_ERR(u);
9068c2ecf20Sopenharmony_ci		}
9078c2ecf20Sopenharmony_ci
9088c2ecf20Sopenharmony_ci		mlx5_ib_cont_pages(u, start, MLX5_MKEY_PAGE_SHIFT_MASK, npages,
9098c2ecf20Sopenharmony_ci				   page_shift, ncont, order);
9108c2ecf20Sopenharmony_ci	}
9118c2ecf20Sopenharmony_ci
9128c2ecf20Sopenharmony_ci	if (!*npages) {
9138c2ecf20Sopenharmony_ci		mlx5_ib_warn(dev, "avoid zero region\n");
9148c2ecf20Sopenharmony_ci		ib_umem_release(u);
9158c2ecf20Sopenharmony_ci		return -EINVAL;
9168c2ecf20Sopenharmony_ci	}
9178c2ecf20Sopenharmony_ci
9188c2ecf20Sopenharmony_ci	*umem = u;
9198c2ecf20Sopenharmony_ci
9208c2ecf20Sopenharmony_ci	mlx5_ib_dbg(dev, "npages %d, ncont %d, order %d, page_shift %d\n",
9218c2ecf20Sopenharmony_ci		    *npages, *ncont, *order, *page_shift);
9228c2ecf20Sopenharmony_ci
9238c2ecf20Sopenharmony_ci	return 0;
9248c2ecf20Sopenharmony_ci}
9258c2ecf20Sopenharmony_ci
9268c2ecf20Sopenharmony_cistatic void mlx5_ib_umr_done(struct ib_cq *cq, struct ib_wc *wc)
9278c2ecf20Sopenharmony_ci{
9288c2ecf20Sopenharmony_ci	struct mlx5_ib_umr_context *context =
9298c2ecf20Sopenharmony_ci		container_of(wc->wr_cqe, struct mlx5_ib_umr_context, cqe);
9308c2ecf20Sopenharmony_ci
9318c2ecf20Sopenharmony_ci	context->status = wc->status;
9328c2ecf20Sopenharmony_ci	complete(&context->done);
9338c2ecf20Sopenharmony_ci}
9348c2ecf20Sopenharmony_ci
9358c2ecf20Sopenharmony_cistatic inline void mlx5_ib_init_umr_context(struct mlx5_ib_umr_context *context)
9368c2ecf20Sopenharmony_ci{
9378c2ecf20Sopenharmony_ci	context->cqe.done = mlx5_ib_umr_done;
9388c2ecf20Sopenharmony_ci	context->status = -1;
9398c2ecf20Sopenharmony_ci	init_completion(&context->done);
9408c2ecf20Sopenharmony_ci}
9418c2ecf20Sopenharmony_ci
9428c2ecf20Sopenharmony_cistatic int mlx5_ib_post_send_wait(struct mlx5_ib_dev *dev,
9438c2ecf20Sopenharmony_ci				  struct mlx5_umr_wr *umrwr)
9448c2ecf20Sopenharmony_ci{
9458c2ecf20Sopenharmony_ci	struct umr_common *umrc = &dev->umrc;
9468c2ecf20Sopenharmony_ci	const struct ib_send_wr *bad;
9478c2ecf20Sopenharmony_ci	int err;
9488c2ecf20Sopenharmony_ci	struct mlx5_ib_umr_context umr_context;
9498c2ecf20Sopenharmony_ci
9508c2ecf20Sopenharmony_ci	mlx5_ib_init_umr_context(&umr_context);
9518c2ecf20Sopenharmony_ci	umrwr->wr.wr_cqe = &umr_context.cqe;
9528c2ecf20Sopenharmony_ci
9538c2ecf20Sopenharmony_ci	down(&umrc->sem);
9548c2ecf20Sopenharmony_ci	err = ib_post_send(umrc->qp, &umrwr->wr, &bad);
9558c2ecf20Sopenharmony_ci	if (err) {
9568c2ecf20Sopenharmony_ci		mlx5_ib_warn(dev, "UMR post send failed, err %d\n", err);
9578c2ecf20Sopenharmony_ci	} else {
9588c2ecf20Sopenharmony_ci		wait_for_completion(&umr_context.done);
9598c2ecf20Sopenharmony_ci		if (umr_context.status != IB_WC_SUCCESS) {
9608c2ecf20Sopenharmony_ci			mlx5_ib_warn(dev, "reg umr failed (%u)\n",
9618c2ecf20Sopenharmony_ci				     umr_context.status);
9628c2ecf20Sopenharmony_ci			err = -EFAULT;
9638c2ecf20Sopenharmony_ci		}
9648c2ecf20Sopenharmony_ci	}
9658c2ecf20Sopenharmony_ci	up(&umrc->sem);
9668c2ecf20Sopenharmony_ci	return err;
9678c2ecf20Sopenharmony_ci}
9688c2ecf20Sopenharmony_ci
9698c2ecf20Sopenharmony_cistatic struct mlx5_cache_ent *mr_cache_ent_from_order(struct mlx5_ib_dev *dev,
9708c2ecf20Sopenharmony_ci						      unsigned int order)
9718c2ecf20Sopenharmony_ci{
9728c2ecf20Sopenharmony_ci	struct mlx5_mr_cache *cache = &dev->cache;
9738c2ecf20Sopenharmony_ci
9748c2ecf20Sopenharmony_ci	if (order < cache->ent[0].order)
9758c2ecf20Sopenharmony_ci		return &cache->ent[0];
9768c2ecf20Sopenharmony_ci	order = order - cache->ent[0].order;
9778c2ecf20Sopenharmony_ci	if (order > MR_CACHE_LAST_STD_ENTRY)
9788c2ecf20Sopenharmony_ci		return NULL;
9798c2ecf20Sopenharmony_ci	return &cache->ent[order];
9808c2ecf20Sopenharmony_ci}
9818c2ecf20Sopenharmony_ci
9828c2ecf20Sopenharmony_cistatic struct mlx5_ib_mr *
9838c2ecf20Sopenharmony_cialloc_mr_from_cache(struct ib_pd *pd, struct ib_umem *umem, u64 virt_addr,
9848c2ecf20Sopenharmony_ci		    u64 len, int npages, int page_shift, unsigned int order,
9858c2ecf20Sopenharmony_ci		    int access_flags)
9868c2ecf20Sopenharmony_ci{
9878c2ecf20Sopenharmony_ci	struct mlx5_ib_dev *dev = to_mdev(pd->device);
9888c2ecf20Sopenharmony_ci	struct mlx5_cache_ent *ent = mr_cache_ent_from_order(dev, order);
9898c2ecf20Sopenharmony_ci	struct mlx5_ib_mr *mr;
9908c2ecf20Sopenharmony_ci
9918c2ecf20Sopenharmony_ci	if (!ent)
9928c2ecf20Sopenharmony_ci		return ERR_PTR(-E2BIG);
9938c2ecf20Sopenharmony_ci
9948c2ecf20Sopenharmony_ci	/* Matches access in alloc_cache_mr() */
9958c2ecf20Sopenharmony_ci	if (!mlx5_ib_can_reconfig_with_umr(dev, 0, access_flags))
9968c2ecf20Sopenharmony_ci		return ERR_PTR(-EOPNOTSUPP);
9978c2ecf20Sopenharmony_ci
9988c2ecf20Sopenharmony_ci	mr = get_cache_mr(ent);
9998c2ecf20Sopenharmony_ci	if (!mr) {
10008c2ecf20Sopenharmony_ci		mr = create_cache_mr(ent);
10018c2ecf20Sopenharmony_ci		if (IS_ERR(mr))
10028c2ecf20Sopenharmony_ci			return mr;
10038c2ecf20Sopenharmony_ci	}
10048c2ecf20Sopenharmony_ci
10058c2ecf20Sopenharmony_ci	mr->ibmr.pd = pd;
10068c2ecf20Sopenharmony_ci	mr->umem = umem;
10078c2ecf20Sopenharmony_ci	mr->access_flags = access_flags;
10088c2ecf20Sopenharmony_ci	mr->desc_size = sizeof(struct mlx5_mtt);
10098c2ecf20Sopenharmony_ci	mr->mmkey.iova = virt_addr;
10108c2ecf20Sopenharmony_ci	mr->mmkey.size = len;
10118c2ecf20Sopenharmony_ci	mr->mmkey.pd = to_mpd(pd)->pdn;
10128c2ecf20Sopenharmony_ci
10138c2ecf20Sopenharmony_ci	return mr;
10148c2ecf20Sopenharmony_ci}
10158c2ecf20Sopenharmony_ci
10168c2ecf20Sopenharmony_ci#define MLX5_MAX_UMR_CHUNK ((1 << (MLX5_MAX_UMR_SHIFT + 4)) - \
10178c2ecf20Sopenharmony_ci			    MLX5_UMR_MTT_ALIGNMENT)
10188c2ecf20Sopenharmony_ci#define MLX5_SPARE_UMR_CHUNK 0x10000
10198c2ecf20Sopenharmony_ci
10208c2ecf20Sopenharmony_ciint mlx5_ib_update_xlt(struct mlx5_ib_mr *mr, u64 idx, int npages,
10218c2ecf20Sopenharmony_ci		       int page_shift, int flags)
10228c2ecf20Sopenharmony_ci{
10238c2ecf20Sopenharmony_ci	struct mlx5_ib_dev *dev = mr->dev;
10248c2ecf20Sopenharmony_ci	struct device *ddev = dev->ib_dev.dev.parent;
10258c2ecf20Sopenharmony_ci	int size;
10268c2ecf20Sopenharmony_ci	void *xlt;
10278c2ecf20Sopenharmony_ci	dma_addr_t dma;
10288c2ecf20Sopenharmony_ci	struct mlx5_umr_wr wr;
10298c2ecf20Sopenharmony_ci	struct ib_sge sg;
10308c2ecf20Sopenharmony_ci	int err = 0;
10318c2ecf20Sopenharmony_ci	int desc_size = (flags & MLX5_IB_UPD_XLT_INDIRECT)
10328c2ecf20Sopenharmony_ci			       ? sizeof(struct mlx5_klm)
10338c2ecf20Sopenharmony_ci			       : sizeof(struct mlx5_mtt);
10348c2ecf20Sopenharmony_ci	const int page_align = MLX5_UMR_MTT_ALIGNMENT / desc_size;
10358c2ecf20Sopenharmony_ci	const int page_mask = page_align - 1;
10368c2ecf20Sopenharmony_ci	size_t pages_mapped = 0;
10378c2ecf20Sopenharmony_ci	size_t pages_to_map = 0;
10388c2ecf20Sopenharmony_ci	size_t pages_iter = 0;
10398c2ecf20Sopenharmony_ci	size_t size_to_map = 0;
10408c2ecf20Sopenharmony_ci	gfp_t gfp;
10418c2ecf20Sopenharmony_ci	bool use_emergency_page = false;
10428c2ecf20Sopenharmony_ci
10438c2ecf20Sopenharmony_ci	if ((flags & MLX5_IB_UPD_XLT_INDIRECT) &&
10448c2ecf20Sopenharmony_ci	    !umr_can_use_indirect_mkey(dev))
10458c2ecf20Sopenharmony_ci		return -EPERM;
10468c2ecf20Sopenharmony_ci
10478c2ecf20Sopenharmony_ci	/* UMR copies MTTs in units of MLX5_UMR_MTT_ALIGNMENT bytes,
10488c2ecf20Sopenharmony_ci	 * so we need to align the offset and length accordingly
10498c2ecf20Sopenharmony_ci	 */
10508c2ecf20Sopenharmony_ci	if (idx & page_mask) {
10518c2ecf20Sopenharmony_ci		npages += idx & page_mask;
10528c2ecf20Sopenharmony_ci		idx &= ~page_mask;
10538c2ecf20Sopenharmony_ci	}
10548c2ecf20Sopenharmony_ci
10558c2ecf20Sopenharmony_ci	gfp = flags & MLX5_IB_UPD_XLT_ATOMIC ? GFP_ATOMIC : GFP_KERNEL;
10568c2ecf20Sopenharmony_ci	gfp |= __GFP_ZERO | __GFP_NOWARN;
10578c2ecf20Sopenharmony_ci
10588c2ecf20Sopenharmony_ci	pages_to_map = ALIGN(npages, page_align);
10598c2ecf20Sopenharmony_ci	size = desc_size * pages_to_map;
10608c2ecf20Sopenharmony_ci	size = min_t(int, size, MLX5_MAX_UMR_CHUNK);
10618c2ecf20Sopenharmony_ci
10628c2ecf20Sopenharmony_ci	xlt = (void *)__get_free_pages(gfp, get_order(size));
10638c2ecf20Sopenharmony_ci	if (!xlt && size > MLX5_SPARE_UMR_CHUNK) {
10648c2ecf20Sopenharmony_ci		mlx5_ib_dbg(dev, "Failed to allocate %d bytes of order %d. fallback to spare UMR allocation od %d bytes\n",
10658c2ecf20Sopenharmony_ci			    size, get_order(size), MLX5_SPARE_UMR_CHUNK);
10668c2ecf20Sopenharmony_ci
10678c2ecf20Sopenharmony_ci		size = MLX5_SPARE_UMR_CHUNK;
10688c2ecf20Sopenharmony_ci		xlt = (void *)__get_free_pages(gfp, get_order(size));
10698c2ecf20Sopenharmony_ci	}
10708c2ecf20Sopenharmony_ci
10718c2ecf20Sopenharmony_ci	if (!xlt) {
10728c2ecf20Sopenharmony_ci		mlx5_ib_warn(dev, "Using XLT emergency buffer\n");
10738c2ecf20Sopenharmony_ci		xlt = (void *)mlx5_ib_get_xlt_emergency_page();
10748c2ecf20Sopenharmony_ci		size = PAGE_SIZE;
10758c2ecf20Sopenharmony_ci		memset(xlt, 0, size);
10768c2ecf20Sopenharmony_ci		use_emergency_page = true;
10778c2ecf20Sopenharmony_ci	}
10788c2ecf20Sopenharmony_ci	pages_iter = size / desc_size;
10798c2ecf20Sopenharmony_ci	dma = dma_map_single(ddev, xlt, size, DMA_TO_DEVICE);
10808c2ecf20Sopenharmony_ci	if (dma_mapping_error(ddev, dma)) {
10818c2ecf20Sopenharmony_ci		mlx5_ib_err(dev, "unable to map DMA during XLT update.\n");
10828c2ecf20Sopenharmony_ci		err = -ENOMEM;
10838c2ecf20Sopenharmony_ci		goto free_xlt;
10848c2ecf20Sopenharmony_ci	}
10858c2ecf20Sopenharmony_ci
10868c2ecf20Sopenharmony_ci	if (mr->umem->is_odp) {
10878c2ecf20Sopenharmony_ci		if (!(flags & MLX5_IB_UPD_XLT_INDIRECT)) {
10888c2ecf20Sopenharmony_ci			struct ib_umem_odp *odp = to_ib_umem_odp(mr->umem);
10898c2ecf20Sopenharmony_ci			size_t max_pages = ib_umem_odp_num_pages(odp) - idx;
10908c2ecf20Sopenharmony_ci
10918c2ecf20Sopenharmony_ci			pages_to_map = min_t(size_t, pages_to_map, max_pages);
10928c2ecf20Sopenharmony_ci		}
10938c2ecf20Sopenharmony_ci	}
10948c2ecf20Sopenharmony_ci
10958c2ecf20Sopenharmony_ci	sg.addr = dma;
10968c2ecf20Sopenharmony_ci	sg.lkey = dev->umrc.pd->local_dma_lkey;
10978c2ecf20Sopenharmony_ci
10988c2ecf20Sopenharmony_ci	memset(&wr, 0, sizeof(wr));
10998c2ecf20Sopenharmony_ci	wr.wr.send_flags = MLX5_IB_SEND_UMR_UPDATE_XLT;
11008c2ecf20Sopenharmony_ci	if (!(flags & MLX5_IB_UPD_XLT_ENABLE))
11018c2ecf20Sopenharmony_ci		wr.wr.send_flags |= MLX5_IB_SEND_UMR_FAIL_IF_FREE;
11028c2ecf20Sopenharmony_ci	wr.wr.sg_list = &sg;
11038c2ecf20Sopenharmony_ci	wr.wr.num_sge = 1;
11048c2ecf20Sopenharmony_ci	wr.wr.opcode = MLX5_IB_WR_UMR;
11058c2ecf20Sopenharmony_ci
11068c2ecf20Sopenharmony_ci	wr.pd = mr->ibmr.pd;
11078c2ecf20Sopenharmony_ci	wr.mkey = mr->mmkey.key;
11088c2ecf20Sopenharmony_ci	wr.length = mr->mmkey.size;
11098c2ecf20Sopenharmony_ci	wr.virt_addr = mr->mmkey.iova;
11108c2ecf20Sopenharmony_ci	wr.access_flags = mr->access_flags;
11118c2ecf20Sopenharmony_ci	wr.page_shift = page_shift;
11128c2ecf20Sopenharmony_ci
11138c2ecf20Sopenharmony_ci	for (pages_mapped = 0;
11148c2ecf20Sopenharmony_ci	     pages_mapped < pages_to_map && !err;
11158c2ecf20Sopenharmony_ci	     pages_mapped += pages_iter, idx += pages_iter) {
11168c2ecf20Sopenharmony_ci		npages = min_t(int, pages_iter, pages_to_map - pages_mapped);
11178c2ecf20Sopenharmony_ci		size_to_map = npages * desc_size;
11188c2ecf20Sopenharmony_ci		dma_sync_single_for_cpu(ddev, dma, size, DMA_TO_DEVICE);
11198c2ecf20Sopenharmony_ci		if (mr->umem->is_odp) {
11208c2ecf20Sopenharmony_ci			mlx5_odp_populate_xlt(xlt, idx, npages, mr, flags);
11218c2ecf20Sopenharmony_ci		} else {
11228c2ecf20Sopenharmony_ci			__mlx5_ib_populate_pas(dev, mr->umem, page_shift, idx,
11238c2ecf20Sopenharmony_ci					       npages, xlt,
11248c2ecf20Sopenharmony_ci					       MLX5_IB_MTT_PRESENT);
11258c2ecf20Sopenharmony_ci			/* Clear padding after the pages
11268c2ecf20Sopenharmony_ci			 * brought from the umem.
11278c2ecf20Sopenharmony_ci			 */
11288c2ecf20Sopenharmony_ci			memset(xlt + size_to_map, 0, size - size_to_map);
11298c2ecf20Sopenharmony_ci		}
11308c2ecf20Sopenharmony_ci		dma_sync_single_for_device(ddev, dma, size, DMA_TO_DEVICE);
11318c2ecf20Sopenharmony_ci
11328c2ecf20Sopenharmony_ci		sg.length = ALIGN(size_to_map, MLX5_UMR_MTT_ALIGNMENT);
11338c2ecf20Sopenharmony_ci
11348c2ecf20Sopenharmony_ci		if (pages_mapped + pages_iter >= pages_to_map) {
11358c2ecf20Sopenharmony_ci			if (flags & MLX5_IB_UPD_XLT_ENABLE)
11368c2ecf20Sopenharmony_ci				wr.wr.send_flags |=
11378c2ecf20Sopenharmony_ci					MLX5_IB_SEND_UMR_ENABLE_MR |
11388c2ecf20Sopenharmony_ci					MLX5_IB_SEND_UMR_UPDATE_PD_ACCESS |
11398c2ecf20Sopenharmony_ci					MLX5_IB_SEND_UMR_UPDATE_TRANSLATION;
11408c2ecf20Sopenharmony_ci			if (flags & MLX5_IB_UPD_XLT_PD ||
11418c2ecf20Sopenharmony_ci			    flags & MLX5_IB_UPD_XLT_ACCESS)
11428c2ecf20Sopenharmony_ci				wr.wr.send_flags |=
11438c2ecf20Sopenharmony_ci					MLX5_IB_SEND_UMR_UPDATE_PD_ACCESS;
11448c2ecf20Sopenharmony_ci			if (flags & MLX5_IB_UPD_XLT_ADDR)
11458c2ecf20Sopenharmony_ci				wr.wr.send_flags |=
11468c2ecf20Sopenharmony_ci					MLX5_IB_SEND_UMR_UPDATE_TRANSLATION;
11478c2ecf20Sopenharmony_ci		}
11488c2ecf20Sopenharmony_ci
11498c2ecf20Sopenharmony_ci		wr.offset = idx * desc_size;
11508c2ecf20Sopenharmony_ci		wr.xlt_size = sg.length;
11518c2ecf20Sopenharmony_ci
11528c2ecf20Sopenharmony_ci		err = mlx5_ib_post_send_wait(dev, &wr);
11538c2ecf20Sopenharmony_ci	}
11548c2ecf20Sopenharmony_ci	dma_unmap_single(ddev, dma, size, DMA_TO_DEVICE);
11558c2ecf20Sopenharmony_ci
11568c2ecf20Sopenharmony_cifree_xlt:
11578c2ecf20Sopenharmony_ci	if (use_emergency_page)
11588c2ecf20Sopenharmony_ci		mlx5_ib_put_xlt_emergency_page();
11598c2ecf20Sopenharmony_ci	else
11608c2ecf20Sopenharmony_ci		free_pages((unsigned long)xlt, get_order(size));
11618c2ecf20Sopenharmony_ci
11628c2ecf20Sopenharmony_ci	return err;
11638c2ecf20Sopenharmony_ci}
11648c2ecf20Sopenharmony_ci
11658c2ecf20Sopenharmony_ci/*
11668c2ecf20Sopenharmony_ci * If ibmr is NULL it will be allocated by reg_create.
11678c2ecf20Sopenharmony_ci * Else, the given ibmr will be used.
11688c2ecf20Sopenharmony_ci */
11698c2ecf20Sopenharmony_cistatic struct mlx5_ib_mr *reg_create(struct ib_mr *ibmr, struct ib_pd *pd,
11708c2ecf20Sopenharmony_ci				     u64 virt_addr, u64 length,
11718c2ecf20Sopenharmony_ci				     struct ib_umem *umem, int npages,
11728c2ecf20Sopenharmony_ci				     int page_shift, int access_flags,
11738c2ecf20Sopenharmony_ci				     bool populate)
11748c2ecf20Sopenharmony_ci{
11758c2ecf20Sopenharmony_ci	struct mlx5_ib_dev *dev = to_mdev(pd->device);
11768c2ecf20Sopenharmony_ci	struct mlx5_ib_mr *mr;
11778c2ecf20Sopenharmony_ci	__be64 *pas;
11788c2ecf20Sopenharmony_ci	void *mkc;
11798c2ecf20Sopenharmony_ci	int inlen;
11808c2ecf20Sopenharmony_ci	u32 *in;
11818c2ecf20Sopenharmony_ci	int err;
11828c2ecf20Sopenharmony_ci	bool pg_cap = !!(MLX5_CAP_GEN(dev->mdev, pg));
11838c2ecf20Sopenharmony_ci
11848c2ecf20Sopenharmony_ci	mr = ibmr ? to_mmr(ibmr) : kzalloc(sizeof(*mr), GFP_KERNEL);
11858c2ecf20Sopenharmony_ci	if (!mr)
11868c2ecf20Sopenharmony_ci		return ERR_PTR(-ENOMEM);
11878c2ecf20Sopenharmony_ci
11888c2ecf20Sopenharmony_ci	mr->ibmr.pd = pd;
11898c2ecf20Sopenharmony_ci	mr->access_flags = access_flags;
11908c2ecf20Sopenharmony_ci
11918c2ecf20Sopenharmony_ci	inlen = MLX5_ST_SZ_BYTES(create_mkey_in);
11928c2ecf20Sopenharmony_ci	if (populate)
11938c2ecf20Sopenharmony_ci		inlen += sizeof(*pas) * roundup(npages, 2);
11948c2ecf20Sopenharmony_ci	in = kvzalloc(inlen, GFP_KERNEL);
11958c2ecf20Sopenharmony_ci	if (!in) {
11968c2ecf20Sopenharmony_ci		err = -ENOMEM;
11978c2ecf20Sopenharmony_ci		goto err_1;
11988c2ecf20Sopenharmony_ci	}
11998c2ecf20Sopenharmony_ci	pas = (__be64 *)MLX5_ADDR_OF(create_mkey_in, in, klm_pas_mtt);
12008c2ecf20Sopenharmony_ci	if (populate) {
12018c2ecf20Sopenharmony_ci		if (WARN_ON(access_flags & IB_ACCESS_ON_DEMAND)) {
12028c2ecf20Sopenharmony_ci			err = -EINVAL;
12038c2ecf20Sopenharmony_ci			goto err_2;
12048c2ecf20Sopenharmony_ci		}
12058c2ecf20Sopenharmony_ci		mlx5_ib_populate_pas(dev, umem, page_shift, pas,
12068c2ecf20Sopenharmony_ci				     pg_cap ? MLX5_IB_MTT_PRESENT : 0);
12078c2ecf20Sopenharmony_ci	}
12088c2ecf20Sopenharmony_ci
12098c2ecf20Sopenharmony_ci	/* The pg_access bit allows setting the access flags
12108c2ecf20Sopenharmony_ci	 * in the page list submitted with the command. */
12118c2ecf20Sopenharmony_ci	MLX5_SET(create_mkey_in, in, pg_access, !!(pg_cap));
12128c2ecf20Sopenharmony_ci
12138c2ecf20Sopenharmony_ci	mkc = MLX5_ADDR_OF(create_mkey_in, in, memory_key_mkey_entry);
12148c2ecf20Sopenharmony_ci	set_mkc_access_pd_addr_fields(mkc, access_flags, virt_addr,
12158c2ecf20Sopenharmony_ci				      populate ? pd : dev->umrc.pd);
12168c2ecf20Sopenharmony_ci	MLX5_SET(mkc, mkc, free, !populate);
12178c2ecf20Sopenharmony_ci	MLX5_SET(mkc, mkc, access_mode_1_0, MLX5_MKC_ACCESS_MODE_MTT);
12188c2ecf20Sopenharmony_ci	MLX5_SET(mkc, mkc, umr_en, 1);
12198c2ecf20Sopenharmony_ci
12208c2ecf20Sopenharmony_ci	MLX5_SET64(mkc, mkc, len, length);
12218c2ecf20Sopenharmony_ci	MLX5_SET(mkc, mkc, bsf_octword_size, 0);
12228c2ecf20Sopenharmony_ci	MLX5_SET(mkc, mkc, translations_octword_size,
12238c2ecf20Sopenharmony_ci		 get_octo_len(virt_addr, length, page_shift));
12248c2ecf20Sopenharmony_ci	MLX5_SET(mkc, mkc, log_page_size, page_shift);
12258c2ecf20Sopenharmony_ci	if (populate) {
12268c2ecf20Sopenharmony_ci		MLX5_SET(create_mkey_in, in, translations_octword_actual_size,
12278c2ecf20Sopenharmony_ci			 get_octo_len(virt_addr, length, page_shift));
12288c2ecf20Sopenharmony_ci	}
12298c2ecf20Sopenharmony_ci
12308c2ecf20Sopenharmony_ci	err = mlx5_ib_create_mkey(dev, &mr->mmkey, in, inlen);
12318c2ecf20Sopenharmony_ci	if (err) {
12328c2ecf20Sopenharmony_ci		mlx5_ib_warn(dev, "create mkey failed\n");
12338c2ecf20Sopenharmony_ci		goto err_2;
12348c2ecf20Sopenharmony_ci	}
12358c2ecf20Sopenharmony_ci	mr->mmkey.type = MLX5_MKEY_MR;
12368c2ecf20Sopenharmony_ci	mr->desc_size = sizeof(struct mlx5_mtt);
12378c2ecf20Sopenharmony_ci	mr->dev = dev;
12388c2ecf20Sopenharmony_ci	kvfree(in);
12398c2ecf20Sopenharmony_ci
12408c2ecf20Sopenharmony_ci	mlx5_ib_dbg(dev, "mkey = 0x%x\n", mr->mmkey.key);
12418c2ecf20Sopenharmony_ci
12428c2ecf20Sopenharmony_ci	return mr;
12438c2ecf20Sopenharmony_ci
12448c2ecf20Sopenharmony_cierr_2:
12458c2ecf20Sopenharmony_ci	kvfree(in);
12468c2ecf20Sopenharmony_ci
12478c2ecf20Sopenharmony_cierr_1:
12488c2ecf20Sopenharmony_ci	if (!ibmr)
12498c2ecf20Sopenharmony_ci		kfree(mr);
12508c2ecf20Sopenharmony_ci
12518c2ecf20Sopenharmony_ci	return ERR_PTR(err);
12528c2ecf20Sopenharmony_ci}
12538c2ecf20Sopenharmony_ci
12548c2ecf20Sopenharmony_cistatic void set_mr_fields(struct mlx5_ib_dev *dev, struct mlx5_ib_mr *mr,
12558c2ecf20Sopenharmony_ci			  u64 length, int access_flags)
12568c2ecf20Sopenharmony_ci{
12578c2ecf20Sopenharmony_ci	mr->ibmr.lkey = mr->mmkey.key;
12588c2ecf20Sopenharmony_ci	mr->ibmr.rkey = mr->mmkey.key;
12598c2ecf20Sopenharmony_ci	mr->ibmr.length = length;
12608c2ecf20Sopenharmony_ci	mr->access_flags = access_flags;
12618c2ecf20Sopenharmony_ci}
12628c2ecf20Sopenharmony_ci
12638c2ecf20Sopenharmony_cistatic struct ib_mr *mlx5_ib_get_dm_mr(struct ib_pd *pd, u64 start_addr,
12648c2ecf20Sopenharmony_ci				       u64 length, int acc, int mode)
12658c2ecf20Sopenharmony_ci{
12668c2ecf20Sopenharmony_ci	struct mlx5_ib_dev *dev = to_mdev(pd->device);
12678c2ecf20Sopenharmony_ci	int inlen = MLX5_ST_SZ_BYTES(create_mkey_in);
12688c2ecf20Sopenharmony_ci	struct mlx5_ib_mr *mr;
12698c2ecf20Sopenharmony_ci	void *mkc;
12708c2ecf20Sopenharmony_ci	u32 *in;
12718c2ecf20Sopenharmony_ci	int err;
12728c2ecf20Sopenharmony_ci
12738c2ecf20Sopenharmony_ci	mr = kzalloc(sizeof(*mr), GFP_KERNEL);
12748c2ecf20Sopenharmony_ci	if (!mr)
12758c2ecf20Sopenharmony_ci		return ERR_PTR(-ENOMEM);
12768c2ecf20Sopenharmony_ci
12778c2ecf20Sopenharmony_ci	in = kzalloc(inlen, GFP_KERNEL);
12788c2ecf20Sopenharmony_ci	if (!in) {
12798c2ecf20Sopenharmony_ci		err = -ENOMEM;
12808c2ecf20Sopenharmony_ci		goto err_free;
12818c2ecf20Sopenharmony_ci	}
12828c2ecf20Sopenharmony_ci
12838c2ecf20Sopenharmony_ci	mkc = MLX5_ADDR_OF(create_mkey_in, in, memory_key_mkey_entry);
12848c2ecf20Sopenharmony_ci
12858c2ecf20Sopenharmony_ci	MLX5_SET(mkc, mkc, access_mode_1_0, mode & 0x3);
12868c2ecf20Sopenharmony_ci	MLX5_SET(mkc, mkc, access_mode_4_2, (mode >> 2) & 0x7);
12878c2ecf20Sopenharmony_ci	MLX5_SET64(mkc, mkc, len, length);
12888c2ecf20Sopenharmony_ci	set_mkc_access_pd_addr_fields(mkc, acc, start_addr, pd);
12898c2ecf20Sopenharmony_ci
12908c2ecf20Sopenharmony_ci	err = mlx5_ib_create_mkey(dev, &mr->mmkey, in, inlen);
12918c2ecf20Sopenharmony_ci	if (err)
12928c2ecf20Sopenharmony_ci		goto err_in;
12938c2ecf20Sopenharmony_ci
12948c2ecf20Sopenharmony_ci	kfree(in);
12958c2ecf20Sopenharmony_ci
12968c2ecf20Sopenharmony_ci	set_mr_fields(dev, mr, length, acc);
12978c2ecf20Sopenharmony_ci
12988c2ecf20Sopenharmony_ci	return &mr->ibmr;
12998c2ecf20Sopenharmony_ci
13008c2ecf20Sopenharmony_cierr_in:
13018c2ecf20Sopenharmony_ci	kfree(in);
13028c2ecf20Sopenharmony_ci
13038c2ecf20Sopenharmony_cierr_free:
13048c2ecf20Sopenharmony_ci	kfree(mr);
13058c2ecf20Sopenharmony_ci
13068c2ecf20Sopenharmony_ci	return ERR_PTR(err);
13078c2ecf20Sopenharmony_ci}
13088c2ecf20Sopenharmony_ci
13098c2ecf20Sopenharmony_ciint mlx5_ib_advise_mr(struct ib_pd *pd,
13108c2ecf20Sopenharmony_ci		      enum ib_uverbs_advise_mr_advice advice,
13118c2ecf20Sopenharmony_ci		      u32 flags,
13128c2ecf20Sopenharmony_ci		      struct ib_sge *sg_list,
13138c2ecf20Sopenharmony_ci		      u32 num_sge,
13148c2ecf20Sopenharmony_ci		      struct uverbs_attr_bundle *attrs)
13158c2ecf20Sopenharmony_ci{
13168c2ecf20Sopenharmony_ci	if (advice != IB_UVERBS_ADVISE_MR_ADVICE_PREFETCH &&
13178c2ecf20Sopenharmony_ci	    advice != IB_UVERBS_ADVISE_MR_ADVICE_PREFETCH_WRITE &&
13188c2ecf20Sopenharmony_ci	    advice != IB_UVERBS_ADVISE_MR_ADVICE_PREFETCH_NO_FAULT)
13198c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
13208c2ecf20Sopenharmony_ci
13218c2ecf20Sopenharmony_ci	return mlx5_ib_advise_mr_prefetch(pd, advice, flags,
13228c2ecf20Sopenharmony_ci					 sg_list, num_sge);
13238c2ecf20Sopenharmony_ci}
13248c2ecf20Sopenharmony_ci
13258c2ecf20Sopenharmony_cistruct ib_mr *mlx5_ib_reg_dm_mr(struct ib_pd *pd, struct ib_dm *dm,
13268c2ecf20Sopenharmony_ci				struct ib_dm_mr_attr *attr,
13278c2ecf20Sopenharmony_ci				struct uverbs_attr_bundle *attrs)
13288c2ecf20Sopenharmony_ci{
13298c2ecf20Sopenharmony_ci	struct mlx5_ib_dm *mdm = to_mdm(dm);
13308c2ecf20Sopenharmony_ci	struct mlx5_core_dev *dev = to_mdev(dm->device)->mdev;
13318c2ecf20Sopenharmony_ci	u64 start_addr = mdm->dev_addr + attr->offset;
13328c2ecf20Sopenharmony_ci	int mode;
13338c2ecf20Sopenharmony_ci
13348c2ecf20Sopenharmony_ci	switch (mdm->type) {
13358c2ecf20Sopenharmony_ci	case MLX5_IB_UAPI_DM_TYPE_MEMIC:
13368c2ecf20Sopenharmony_ci		if (attr->access_flags & ~MLX5_IB_DM_MEMIC_ALLOWED_ACCESS)
13378c2ecf20Sopenharmony_ci			return ERR_PTR(-EINVAL);
13388c2ecf20Sopenharmony_ci
13398c2ecf20Sopenharmony_ci		mode = MLX5_MKC_ACCESS_MODE_MEMIC;
13408c2ecf20Sopenharmony_ci		start_addr -= pci_resource_start(dev->pdev, 0);
13418c2ecf20Sopenharmony_ci		break;
13428c2ecf20Sopenharmony_ci	case MLX5_IB_UAPI_DM_TYPE_STEERING_SW_ICM:
13438c2ecf20Sopenharmony_ci	case MLX5_IB_UAPI_DM_TYPE_HEADER_MODIFY_SW_ICM:
13448c2ecf20Sopenharmony_ci		if (attr->access_flags & ~MLX5_IB_DM_SW_ICM_ALLOWED_ACCESS)
13458c2ecf20Sopenharmony_ci			return ERR_PTR(-EINVAL);
13468c2ecf20Sopenharmony_ci
13478c2ecf20Sopenharmony_ci		mode = MLX5_MKC_ACCESS_MODE_SW_ICM;
13488c2ecf20Sopenharmony_ci		break;
13498c2ecf20Sopenharmony_ci	default:
13508c2ecf20Sopenharmony_ci		return ERR_PTR(-EINVAL);
13518c2ecf20Sopenharmony_ci	}
13528c2ecf20Sopenharmony_ci
13538c2ecf20Sopenharmony_ci	return mlx5_ib_get_dm_mr(pd, start_addr, attr->length,
13548c2ecf20Sopenharmony_ci				 attr->access_flags, mode);
13558c2ecf20Sopenharmony_ci}
13568c2ecf20Sopenharmony_ci
13578c2ecf20Sopenharmony_cistruct ib_mr *mlx5_ib_reg_user_mr(struct ib_pd *pd, u64 start, u64 length,
13588c2ecf20Sopenharmony_ci				  u64 virt_addr, int access_flags,
13598c2ecf20Sopenharmony_ci				  struct ib_udata *udata)
13608c2ecf20Sopenharmony_ci{
13618c2ecf20Sopenharmony_ci	struct mlx5_ib_dev *dev = to_mdev(pd->device);
13628c2ecf20Sopenharmony_ci	struct mlx5_ib_mr *mr = NULL;
13638c2ecf20Sopenharmony_ci	bool xlt_with_umr;
13648c2ecf20Sopenharmony_ci	struct ib_umem *umem;
13658c2ecf20Sopenharmony_ci	int page_shift;
13668c2ecf20Sopenharmony_ci	int npages;
13678c2ecf20Sopenharmony_ci	int ncont;
13688c2ecf20Sopenharmony_ci	int order;
13698c2ecf20Sopenharmony_ci	int err;
13708c2ecf20Sopenharmony_ci
13718c2ecf20Sopenharmony_ci	if (!IS_ENABLED(CONFIG_INFINIBAND_USER_MEM))
13728c2ecf20Sopenharmony_ci		return ERR_PTR(-EOPNOTSUPP);
13738c2ecf20Sopenharmony_ci
13748c2ecf20Sopenharmony_ci	mlx5_ib_dbg(dev, "start 0x%llx, virt_addr 0x%llx, length 0x%llx, access_flags 0x%x\n",
13758c2ecf20Sopenharmony_ci		    start, virt_addr, length, access_flags);
13768c2ecf20Sopenharmony_ci
13778c2ecf20Sopenharmony_ci	xlt_with_umr = mlx5_ib_can_load_pas_with_umr(dev, length);
13788c2ecf20Sopenharmony_ci	/* ODP requires xlt update via umr to work. */
13798c2ecf20Sopenharmony_ci	if (!xlt_with_umr && (access_flags & IB_ACCESS_ON_DEMAND))
13808c2ecf20Sopenharmony_ci		return ERR_PTR(-EINVAL);
13818c2ecf20Sopenharmony_ci
13828c2ecf20Sopenharmony_ci	if (IS_ENABLED(CONFIG_INFINIBAND_ON_DEMAND_PAGING) && !start &&
13838c2ecf20Sopenharmony_ci	    length == U64_MAX) {
13848c2ecf20Sopenharmony_ci		if (virt_addr != start)
13858c2ecf20Sopenharmony_ci			return ERR_PTR(-EINVAL);
13868c2ecf20Sopenharmony_ci		if (!(access_flags & IB_ACCESS_ON_DEMAND) ||
13878c2ecf20Sopenharmony_ci		    !(dev->odp_caps.general_caps & IB_ODP_SUPPORT_IMPLICIT))
13888c2ecf20Sopenharmony_ci			return ERR_PTR(-EINVAL);
13898c2ecf20Sopenharmony_ci
13908c2ecf20Sopenharmony_ci		mr = mlx5_ib_alloc_implicit_mr(to_mpd(pd), udata, access_flags);
13918c2ecf20Sopenharmony_ci		if (IS_ERR(mr))
13928c2ecf20Sopenharmony_ci			return ERR_CAST(mr);
13938c2ecf20Sopenharmony_ci		return &mr->ibmr;
13948c2ecf20Sopenharmony_ci	}
13958c2ecf20Sopenharmony_ci
13968c2ecf20Sopenharmony_ci	err = mr_umem_get(dev, start, length, access_flags, &umem,
13978c2ecf20Sopenharmony_ci			  &npages, &page_shift, &ncont, &order);
13988c2ecf20Sopenharmony_ci
13998c2ecf20Sopenharmony_ci	if (err < 0)
14008c2ecf20Sopenharmony_ci		return ERR_PTR(err);
14018c2ecf20Sopenharmony_ci
14028c2ecf20Sopenharmony_ci	if (xlt_with_umr) {
14038c2ecf20Sopenharmony_ci		mr = alloc_mr_from_cache(pd, umem, virt_addr, length, ncont,
14048c2ecf20Sopenharmony_ci					 page_shift, order, access_flags);
14058c2ecf20Sopenharmony_ci		if (IS_ERR(mr))
14068c2ecf20Sopenharmony_ci			mr = NULL;
14078c2ecf20Sopenharmony_ci	}
14088c2ecf20Sopenharmony_ci
14098c2ecf20Sopenharmony_ci	if (!mr) {
14108c2ecf20Sopenharmony_ci		mutex_lock(&dev->slow_path_mutex);
14118c2ecf20Sopenharmony_ci		mr = reg_create(NULL, pd, virt_addr, length, umem, ncont,
14128c2ecf20Sopenharmony_ci				page_shift, access_flags, !xlt_with_umr);
14138c2ecf20Sopenharmony_ci		mutex_unlock(&dev->slow_path_mutex);
14148c2ecf20Sopenharmony_ci	}
14158c2ecf20Sopenharmony_ci
14168c2ecf20Sopenharmony_ci	if (IS_ERR(mr)) {
14178c2ecf20Sopenharmony_ci		err = PTR_ERR(mr);
14188c2ecf20Sopenharmony_ci		goto error;
14198c2ecf20Sopenharmony_ci	}
14208c2ecf20Sopenharmony_ci
14218c2ecf20Sopenharmony_ci	mlx5_ib_dbg(dev, "mkey 0x%x\n", mr->mmkey.key);
14228c2ecf20Sopenharmony_ci
14238c2ecf20Sopenharmony_ci	mr->umem = umem;
14248c2ecf20Sopenharmony_ci	mr->npages = npages;
14258c2ecf20Sopenharmony_ci	atomic_add(mr->npages, &dev->mdev->priv.reg_pages);
14268c2ecf20Sopenharmony_ci	set_mr_fields(dev, mr, length, access_flags);
14278c2ecf20Sopenharmony_ci
14288c2ecf20Sopenharmony_ci	if (xlt_with_umr && !(access_flags & IB_ACCESS_ON_DEMAND)) {
14298c2ecf20Sopenharmony_ci		/*
14308c2ecf20Sopenharmony_ci		 * If the MR was created with reg_create then it will be
14318c2ecf20Sopenharmony_ci		 * configured properly but left disabled. It is safe to go ahead
14328c2ecf20Sopenharmony_ci		 * and configure it again via UMR while enabling it.
14338c2ecf20Sopenharmony_ci		 */
14348c2ecf20Sopenharmony_ci		int update_xlt_flags = MLX5_IB_UPD_XLT_ENABLE;
14358c2ecf20Sopenharmony_ci
14368c2ecf20Sopenharmony_ci		err = mlx5_ib_update_xlt(mr, 0, ncont, page_shift,
14378c2ecf20Sopenharmony_ci					 update_xlt_flags);
14388c2ecf20Sopenharmony_ci		if (err) {
14398c2ecf20Sopenharmony_ci			dereg_mr(dev, mr);
14408c2ecf20Sopenharmony_ci			return ERR_PTR(err);
14418c2ecf20Sopenharmony_ci		}
14428c2ecf20Sopenharmony_ci	}
14438c2ecf20Sopenharmony_ci
14448c2ecf20Sopenharmony_ci	if (is_odp_mr(mr)) {
14458c2ecf20Sopenharmony_ci		to_ib_umem_odp(mr->umem)->private = mr;
14468c2ecf20Sopenharmony_ci		init_waitqueue_head(&mr->q_deferred_work);
14478c2ecf20Sopenharmony_ci		atomic_set(&mr->num_deferred_work, 0);
14488c2ecf20Sopenharmony_ci		err = xa_err(xa_store(&dev->odp_mkeys,
14498c2ecf20Sopenharmony_ci				      mlx5_base_mkey(mr->mmkey.key), &mr->mmkey,
14508c2ecf20Sopenharmony_ci				      GFP_KERNEL));
14518c2ecf20Sopenharmony_ci		if (err) {
14528c2ecf20Sopenharmony_ci			dereg_mr(dev, mr);
14538c2ecf20Sopenharmony_ci			return ERR_PTR(err);
14548c2ecf20Sopenharmony_ci		}
14558c2ecf20Sopenharmony_ci
14568c2ecf20Sopenharmony_ci		err = mlx5_ib_init_odp_mr(mr, xlt_with_umr);
14578c2ecf20Sopenharmony_ci		if (err) {
14588c2ecf20Sopenharmony_ci			dereg_mr(dev, mr);
14598c2ecf20Sopenharmony_ci			return ERR_PTR(err);
14608c2ecf20Sopenharmony_ci		}
14618c2ecf20Sopenharmony_ci	}
14628c2ecf20Sopenharmony_ci
14638c2ecf20Sopenharmony_ci	return &mr->ibmr;
14648c2ecf20Sopenharmony_cierror:
14658c2ecf20Sopenharmony_ci	ib_umem_release(umem);
14668c2ecf20Sopenharmony_ci	return ERR_PTR(err);
14678c2ecf20Sopenharmony_ci}
14688c2ecf20Sopenharmony_ci
14698c2ecf20Sopenharmony_ci/**
14708c2ecf20Sopenharmony_ci * mlx5_mr_cache_invalidate - Fence all DMA on the MR
14718c2ecf20Sopenharmony_ci * @mr: The MR to fence
14728c2ecf20Sopenharmony_ci *
14738c2ecf20Sopenharmony_ci * Upon return the NIC will not be doing any DMA to the pages under the MR,
14748c2ecf20Sopenharmony_ci * and any DMA inprogress will be completed. Failure of this function
14758c2ecf20Sopenharmony_ci * indicates the HW has failed catastrophically.
14768c2ecf20Sopenharmony_ci */
14778c2ecf20Sopenharmony_ciint mlx5_mr_cache_invalidate(struct mlx5_ib_mr *mr)
14788c2ecf20Sopenharmony_ci{
14798c2ecf20Sopenharmony_ci	struct mlx5_umr_wr umrwr = {};
14808c2ecf20Sopenharmony_ci
14818c2ecf20Sopenharmony_ci	if (mr->dev->mdev->state == MLX5_DEVICE_STATE_INTERNAL_ERROR)
14828c2ecf20Sopenharmony_ci		return 0;
14838c2ecf20Sopenharmony_ci
14848c2ecf20Sopenharmony_ci	umrwr.wr.send_flags = MLX5_IB_SEND_UMR_DISABLE_MR |
14858c2ecf20Sopenharmony_ci			      MLX5_IB_SEND_UMR_UPDATE_PD_ACCESS;
14868c2ecf20Sopenharmony_ci	umrwr.wr.opcode = MLX5_IB_WR_UMR;
14878c2ecf20Sopenharmony_ci	umrwr.pd = mr->dev->umrc.pd;
14888c2ecf20Sopenharmony_ci	umrwr.mkey = mr->mmkey.key;
14898c2ecf20Sopenharmony_ci	umrwr.ignore_free_state = 1;
14908c2ecf20Sopenharmony_ci
14918c2ecf20Sopenharmony_ci	return mlx5_ib_post_send_wait(mr->dev, &umrwr);
14928c2ecf20Sopenharmony_ci}
14938c2ecf20Sopenharmony_ci
14948c2ecf20Sopenharmony_cistatic int rereg_umr(struct ib_pd *pd, struct mlx5_ib_mr *mr,
14958c2ecf20Sopenharmony_ci		     int access_flags, int flags)
14968c2ecf20Sopenharmony_ci{
14978c2ecf20Sopenharmony_ci	struct mlx5_ib_dev *dev = to_mdev(pd->device);
14988c2ecf20Sopenharmony_ci	struct mlx5_umr_wr umrwr = {};
14998c2ecf20Sopenharmony_ci	int err;
15008c2ecf20Sopenharmony_ci
15018c2ecf20Sopenharmony_ci	umrwr.wr.send_flags = MLX5_IB_SEND_UMR_FAIL_IF_FREE;
15028c2ecf20Sopenharmony_ci
15038c2ecf20Sopenharmony_ci	umrwr.wr.opcode = MLX5_IB_WR_UMR;
15048c2ecf20Sopenharmony_ci	umrwr.mkey = mr->mmkey.key;
15058c2ecf20Sopenharmony_ci
15068c2ecf20Sopenharmony_ci	if (flags & IB_MR_REREG_PD || flags & IB_MR_REREG_ACCESS) {
15078c2ecf20Sopenharmony_ci		umrwr.pd = pd;
15088c2ecf20Sopenharmony_ci		umrwr.access_flags = access_flags;
15098c2ecf20Sopenharmony_ci		umrwr.wr.send_flags |= MLX5_IB_SEND_UMR_UPDATE_PD_ACCESS;
15108c2ecf20Sopenharmony_ci	}
15118c2ecf20Sopenharmony_ci
15128c2ecf20Sopenharmony_ci	err = mlx5_ib_post_send_wait(dev, &umrwr);
15138c2ecf20Sopenharmony_ci
15148c2ecf20Sopenharmony_ci	return err;
15158c2ecf20Sopenharmony_ci}
15168c2ecf20Sopenharmony_ci
15178c2ecf20Sopenharmony_ciint mlx5_ib_rereg_user_mr(struct ib_mr *ib_mr, int flags, u64 start,
15188c2ecf20Sopenharmony_ci			  u64 length, u64 virt_addr, int new_access_flags,
15198c2ecf20Sopenharmony_ci			  struct ib_pd *new_pd, struct ib_udata *udata)
15208c2ecf20Sopenharmony_ci{
15218c2ecf20Sopenharmony_ci	struct mlx5_ib_dev *dev = to_mdev(ib_mr->device);
15228c2ecf20Sopenharmony_ci	struct mlx5_ib_mr *mr = to_mmr(ib_mr);
15238c2ecf20Sopenharmony_ci	struct ib_pd *pd = (flags & IB_MR_REREG_PD) ? new_pd : ib_mr->pd;
15248c2ecf20Sopenharmony_ci	int access_flags = flags & IB_MR_REREG_ACCESS ?
15258c2ecf20Sopenharmony_ci			    new_access_flags :
15268c2ecf20Sopenharmony_ci			    mr->access_flags;
15278c2ecf20Sopenharmony_ci	int page_shift = 0;
15288c2ecf20Sopenharmony_ci	int upd_flags = 0;
15298c2ecf20Sopenharmony_ci	int npages = 0;
15308c2ecf20Sopenharmony_ci	int ncont = 0;
15318c2ecf20Sopenharmony_ci	int order = 0;
15328c2ecf20Sopenharmony_ci	u64 addr, len;
15338c2ecf20Sopenharmony_ci	int err;
15348c2ecf20Sopenharmony_ci
15358c2ecf20Sopenharmony_ci	mlx5_ib_dbg(dev, "start 0x%llx, virt_addr 0x%llx, length 0x%llx, access_flags 0x%x\n",
15368c2ecf20Sopenharmony_ci		    start, virt_addr, length, access_flags);
15378c2ecf20Sopenharmony_ci
15388c2ecf20Sopenharmony_ci	if (!mr->umem)
15398c2ecf20Sopenharmony_ci		return -EINVAL;
15408c2ecf20Sopenharmony_ci
15418c2ecf20Sopenharmony_ci	if (is_odp_mr(mr))
15428c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
15438c2ecf20Sopenharmony_ci
15448c2ecf20Sopenharmony_ci	if (flags & IB_MR_REREG_TRANS) {
15458c2ecf20Sopenharmony_ci		addr = virt_addr;
15468c2ecf20Sopenharmony_ci		len = length;
15478c2ecf20Sopenharmony_ci	} else {
15488c2ecf20Sopenharmony_ci		addr = mr->umem->address;
15498c2ecf20Sopenharmony_ci		len = mr->umem->length;
15508c2ecf20Sopenharmony_ci	}
15518c2ecf20Sopenharmony_ci
15528c2ecf20Sopenharmony_ci	if (flags != IB_MR_REREG_PD) {
15538c2ecf20Sopenharmony_ci		/*
15548c2ecf20Sopenharmony_ci		 * Replace umem. This needs to be done whether or not UMR is
15558c2ecf20Sopenharmony_ci		 * used.
15568c2ecf20Sopenharmony_ci		 */
15578c2ecf20Sopenharmony_ci		flags |= IB_MR_REREG_TRANS;
15588c2ecf20Sopenharmony_ci		atomic_sub(mr->npages, &dev->mdev->priv.reg_pages);
15598c2ecf20Sopenharmony_ci		mr->npages = 0;
15608c2ecf20Sopenharmony_ci		ib_umem_release(mr->umem);
15618c2ecf20Sopenharmony_ci		mr->umem = NULL;
15628c2ecf20Sopenharmony_ci
15638c2ecf20Sopenharmony_ci		err = mr_umem_get(dev, addr, len, access_flags, &mr->umem,
15648c2ecf20Sopenharmony_ci				  &npages, &page_shift, &ncont, &order);
15658c2ecf20Sopenharmony_ci		if (err)
15668c2ecf20Sopenharmony_ci			goto err;
15678c2ecf20Sopenharmony_ci		mr->npages = ncont;
15688c2ecf20Sopenharmony_ci		atomic_add(mr->npages, &dev->mdev->priv.reg_pages);
15698c2ecf20Sopenharmony_ci	}
15708c2ecf20Sopenharmony_ci
15718c2ecf20Sopenharmony_ci	if (!mlx5_ib_can_reconfig_with_umr(dev, mr->access_flags,
15728c2ecf20Sopenharmony_ci					   access_flags) ||
15738c2ecf20Sopenharmony_ci	    !mlx5_ib_can_load_pas_with_umr(dev, len) ||
15748c2ecf20Sopenharmony_ci	    (flags & IB_MR_REREG_TRANS &&
15758c2ecf20Sopenharmony_ci	     !mlx5_ib_pas_fits_in_mr(mr, addr, len))) {
15768c2ecf20Sopenharmony_ci		/*
15778c2ecf20Sopenharmony_ci		 * UMR can't be used - MKey needs to be replaced.
15788c2ecf20Sopenharmony_ci		 */
15798c2ecf20Sopenharmony_ci		if (mr->cache_ent)
15808c2ecf20Sopenharmony_ci			detach_mr_from_cache(mr);
15818c2ecf20Sopenharmony_ci		err = destroy_mkey(dev, mr);
15828c2ecf20Sopenharmony_ci		if (err)
15838c2ecf20Sopenharmony_ci			goto err;
15848c2ecf20Sopenharmony_ci
15858c2ecf20Sopenharmony_ci		mr = reg_create(ib_mr, pd, addr, len, mr->umem, ncont,
15868c2ecf20Sopenharmony_ci				page_shift, access_flags, true);
15878c2ecf20Sopenharmony_ci
15888c2ecf20Sopenharmony_ci		if (IS_ERR(mr)) {
15898c2ecf20Sopenharmony_ci			err = PTR_ERR(mr);
15908c2ecf20Sopenharmony_ci			mr = to_mmr(ib_mr);
15918c2ecf20Sopenharmony_ci			goto err;
15928c2ecf20Sopenharmony_ci		}
15938c2ecf20Sopenharmony_ci	} else {
15948c2ecf20Sopenharmony_ci		/*
15958c2ecf20Sopenharmony_ci		 * Send a UMR WQE
15968c2ecf20Sopenharmony_ci		 */
15978c2ecf20Sopenharmony_ci		mr->ibmr.pd = pd;
15988c2ecf20Sopenharmony_ci		mr->access_flags = access_flags;
15998c2ecf20Sopenharmony_ci		mr->mmkey.iova = addr;
16008c2ecf20Sopenharmony_ci		mr->mmkey.size = len;
16018c2ecf20Sopenharmony_ci		mr->mmkey.pd = to_mpd(pd)->pdn;
16028c2ecf20Sopenharmony_ci
16038c2ecf20Sopenharmony_ci		if (flags & IB_MR_REREG_TRANS) {
16048c2ecf20Sopenharmony_ci			upd_flags = MLX5_IB_UPD_XLT_ADDR;
16058c2ecf20Sopenharmony_ci			if (flags & IB_MR_REREG_PD)
16068c2ecf20Sopenharmony_ci				upd_flags |= MLX5_IB_UPD_XLT_PD;
16078c2ecf20Sopenharmony_ci			if (flags & IB_MR_REREG_ACCESS)
16088c2ecf20Sopenharmony_ci				upd_flags |= MLX5_IB_UPD_XLT_ACCESS;
16098c2ecf20Sopenharmony_ci			err = mlx5_ib_update_xlt(mr, 0, npages, page_shift,
16108c2ecf20Sopenharmony_ci						 upd_flags);
16118c2ecf20Sopenharmony_ci		} else {
16128c2ecf20Sopenharmony_ci			err = rereg_umr(pd, mr, access_flags, flags);
16138c2ecf20Sopenharmony_ci		}
16148c2ecf20Sopenharmony_ci
16158c2ecf20Sopenharmony_ci		if (err)
16168c2ecf20Sopenharmony_ci			goto err;
16178c2ecf20Sopenharmony_ci	}
16188c2ecf20Sopenharmony_ci
16198c2ecf20Sopenharmony_ci	set_mr_fields(dev, mr, len, access_flags);
16208c2ecf20Sopenharmony_ci
16218c2ecf20Sopenharmony_ci	return 0;
16228c2ecf20Sopenharmony_ci
16238c2ecf20Sopenharmony_cierr:
16248c2ecf20Sopenharmony_ci	ib_umem_release(mr->umem);
16258c2ecf20Sopenharmony_ci	mr->umem = NULL;
16268c2ecf20Sopenharmony_ci
16278c2ecf20Sopenharmony_ci	clean_mr(dev, mr);
16288c2ecf20Sopenharmony_ci	return err;
16298c2ecf20Sopenharmony_ci}
16308c2ecf20Sopenharmony_ci
16318c2ecf20Sopenharmony_cistatic int
16328c2ecf20Sopenharmony_cimlx5_alloc_priv_descs(struct ib_device *device,
16338c2ecf20Sopenharmony_ci		      struct mlx5_ib_mr *mr,
16348c2ecf20Sopenharmony_ci		      int ndescs,
16358c2ecf20Sopenharmony_ci		      int desc_size)
16368c2ecf20Sopenharmony_ci{
16378c2ecf20Sopenharmony_ci	int size = ndescs * desc_size;
16388c2ecf20Sopenharmony_ci	int add_size;
16398c2ecf20Sopenharmony_ci	int ret;
16408c2ecf20Sopenharmony_ci
16418c2ecf20Sopenharmony_ci	add_size = max_t(int, MLX5_UMR_ALIGN - ARCH_KMALLOC_MINALIGN, 0);
16428c2ecf20Sopenharmony_ci
16438c2ecf20Sopenharmony_ci	mr->descs_alloc = kzalloc(size + add_size, GFP_KERNEL);
16448c2ecf20Sopenharmony_ci	if (!mr->descs_alloc)
16458c2ecf20Sopenharmony_ci		return -ENOMEM;
16468c2ecf20Sopenharmony_ci
16478c2ecf20Sopenharmony_ci	mr->descs = PTR_ALIGN(mr->descs_alloc, MLX5_UMR_ALIGN);
16488c2ecf20Sopenharmony_ci
16498c2ecf20Sopenharmony_ci	mr->desc_map = dma_map_single(device->dev.parent, mr->descs,
16508c2ecf20Sopenharmony_ci				      size, DMA_TO_DEVICE);
16518c2ecf20Sopenharmony_ci	if (dma_mapping_error(device->dev.parent, mr->desc_map)) {
16528c2ecf20Sopenharmony_ci		ret = -ENOMEM;
16538c2ecf20Sopenharmony_ci		goto err;
16548c2ecf20Sopenharmony_ci	}
16558c2ecf20Sopenharmony_ci
16568c2ecf20Sopenharmony_ci	return 0;
16578c2ecf20Sopenharmony_cierr:
16588c2ecf20Sopenharmony_ci	kfree(mr->descs_alloc);
16598c2ecf20Sopenharmony_ci
16608c2ecf20Sopenharmony_ci	return ret;
16618c2ecf20Sopenharmony_ci}
16628c2ecf20Sopenharmony_ci
16638c2ecf20Sopenharmony_cistatic void
16648c2ecf20Sopenharmony_cimlx5_free_priv_descs(struct mlx5_ib_mr *mr)
16658c2ecf20Sopenharmony_ci{
16668c2ecf20Sopenharmony_ci	if (mr->descs) {
16678c2ecf20Sopenharmony_ci		struct ib_device *device = mr->ibmr.device;
16688c2ecf20Sopenharmony_ci		int size = mr->max_descs * mr->desc_size;
16698c2ecf20Sopenharmony_ci
16708c2ecf20Sopenharmony_ci		dma_unmap_single(device->dev.parent, mr->desc_map,
16718c2ecf20Sopenharmony_ci				 size, DMA_TO_DEVICE);
16728c2ecf20Sopenharmony_ci		kfree(mr->descs_alloc);
16738c2ecf20Sopenharmony_ci		mr->descs = NULL;
16748c2ecf20Sopenharmony_ci	}
16758c2ecf20Sopenharmony_ci}
16768c2ecf20Sopenharmony_ci
16778c2ecf20Sopenharmony_cistatic void clean_mr(struct mlx5_ib_dev *dev, struct mlx5_ib_mr *mr)
16788c2ecf20Sopenharmony_ci{
16798c2ecf20Sopenharmony_ci	if (mr->sig) {
16808c2ecf20Sopenharmony_ci		if (mlx5_core_destroy_psv(dev->mdev,
16818c2ecf20Sopenharmony_ci					  mr->sig->psv_memory.psv_idx))
16828c2ecf20Sopenharmony_ci			mlx5_ib_warn(dev, "failed to destroy mem psv %d\n",
16838c2ecf20Sopenharmony_ci				     mr->sig->psv_memory.psv_idx);
16848c2ecf20Sopenharmony_ci		if (mlx5_core_destroy_psv(dev->mdev,
16858c2ecf20Sopenharmony_ci					  mr->sig->psv_wire.psv_idx))
16868c2ecf20Sopenharmony_ci			mlx5_ib_warn(dev, "failed to destroy wire psv %d\n",
16878c2ecf20Sopenharmony_ci				     mr->sig->psv_wire.psv_idx);
16888c2ecf20Sopenharmony_ci		xa_erase(&dev->sig_mrs, mlx5_base_mkey(mr->mmkey.key));
16898c2ecf20Sopenharmony_ci		kfree(mr->sig);
16908c2ecf20Sopenharmony_ci		mr->sig = NULL;
16918c2ecf20Sopenharmony_ci	}
16928c2ecf20Sopenharmony_ci
16938c2ecf20Sopenharmony_ci	if (!mr->cache_ent) {
16948c2ecf20Sopenharmony_ci		destroy_mkey(dev, mr);
16958c2ecf20Sopenharmony_ci		mlx5_free_priv_descs(mr);
16968c2ecf20Sopenharmony_ci	}
16978c2ecf20Sopenharmony_ci}
16988c2ecf20Sopenharmony_ci
16998c2ecf20Sopenharmony_cistatic void dereg_mr(struct mlx5_ib_dev *dev, struct mlx5_ib_mr *mr)
17008c2ecf20Sopenharmony_ci{
17018c2ecf20Sopenharmony_ci	int npages = mr->npages;
17028c2ecf20Sopenharmony_ci	struct ib_umem *umem = mr->umem;
17038c2ecf20Sopenharmony_ci
17048c2ecf20Sopenharmony_ci	/* Stop all DMA */
17058c2ecf20Sopenharmony_ci	if (is_odp_mr(mr))
17068c2ecf20Sopenharmony_ci		mlx5_ib_fence_odp_mr(mr);
17078c2ecf20Sopenharmony_ci	else
17088c2ecf20Sopenharmony_ci		clean_mr(dev, mr);
17098c2ecf20Sopenharmony_ci
17108c2ecf20Sopenharmony_ci	if (mr->cache_ent)
17118c2ecf20Sopenharmony_ci		mlx5_mr_cache_free(dev, mr);
17128c2ecf20Sopenharmony_ci	else
17138c2ecf20Sopenharmony_ci		kfree(mr);
17148c2ecf20Sopenharmony_ci
17158c2ecf20Sopenharmony_ci	ib_umem_release(umem);
17168c2ecf20Sopenharmony_ci	atomic_sub(npages, &dev->mdev->priv.reg_pages);
17178c2ecf20Sopenharmony_ci
17188c2ecf20Sopenharmony_ci}
17198c2ecf20Sopenharmony_ci
17208c2ecf20Sopenharmony_ciint mlx5_ib_dereg_mr(struct ib_mr *ibmr, struct ib_udata *udata)
17218c2ecf20Sopenharmony_ci{
17228c2ecf20Sopenharmony_ci	struct mlx5_ib_mr *mmr = to_mmr(ibmr);
17238c2ecf20Sopenharmony_ci
17248c2ecf20Sopenharmony_ci	if (ibmr->type == IB_MR_TYPE_INTEGRITY) {
17258c2ecf20Sopenharmony_ci		dereg_mr(to_mdev(mmr->mtt_mr->ibmr.device), mmr->mtt_mr);
17268c2ecf20Sopenharmony_ci		dereg_mr(to_mdev(mmr->klm_mr->ibmr.device), mmr->klm_mr);
17278c2ecf20Sopenharmony_ci	}
17288c2ecf20Sopenharmony_ci
17298c2ecf20Sopenharmony_ci	if (is_odp_mr(mmr) && to_ib_umem_odp(mmr->umem)->is_implicit_odp) {
17308c2ecf20Sopenharmony_ci		mlx5_ib_free_implicit_mr(mmr);
17318c2ecf20Sopenharmony_ci		return 0;
17328c2ecf20Sopenharmony_ci	}
17338c2ecf20Sopenharmony_ci
17348c2ecf20Sopenharmony_ci	dereg_mr(to_mdev(ibmr->device), mmr);
17358c2ecf20Sopenharmony_ci
17368c2ecf20Sopenharmony_ci	return 0;
17378c2ecf20Sopenharmony_ci}
17388c2ecf20Sopenharmony_ci
17398c2ecf20Sopenharmony_cistatic void mlx5_set_umr_free_mkey(struct ib_pd *pd, u32 *in, int ndescs,
17408c2ecf20Sopenharmony_ci				   int access_mode, int page_shift)
17418c2ecf20Sopenharmony_ci{
17428c2ecf20Sopenharmony_ci	void *mkc;
17438c2ecf20Sopenharmony_ci
17448c2ecf20Sopenharmony_ci	mkc = MLX5_ADDR_OF(create_mkey_in, in, memory_key_mkey_entry);
17458c2ecf20Sopenharmony_ci
17468c2ecf20Sopenharmony_ci	/* This is only used from the kernel, so setting the PD is OK. */
17478c2ecf20Sopenharmony_ci	set_mkc_access_pd_addr_fields(mkc, 0, 0, pd);
17488c2ecf20Sopenharmony_ci	MLX5_SET(mkc, mkc, free, 1);
17498c2ecf20Sopenharmony_ci	MLX5_SET(mkc, mkc, translations_octword_size, ndescs);
17508c2ecf20Sopenharmony_ci	MLX5_SET(mkc, mkc, access_mode_1_0, access_mode & 0x3);
17518c2ecf20Sopenharmony_ci	MLX5_SET(mkc, mkc, access_mode_4_2, (access_mode >> 2) & 0x7);
17528c2ecf20Sopenharmony_ci	MLX5_SET(mkc, mkc, umr_en, 1);
17538c2ecf20Sopenharmony_ci	MLX5_SET(mkc, mkc, log_page_size, page_shift);
17548c2ecf20Sopenharmony_ci}
17558c2ecf20Sopenharmony_ci
17568c2ecf20Sopenharmony_cistatic int _mlx5_alloc_mkey_descs(struct ib_pd *pd, struct mlx5_ib_mr *mr,
17578c2ecf20Sopenharmony_ci				  int ndescs, int desc_size, int page_shift,
17588c2ecf20Sopenharmony_ci				  int access_mode, u32 *in, int inlen)
17598c2ecf20Sopenharmony_ci{
17608c2ecf20Sopenharmony_ci	struct mlx5_ib_dev *dev = to_mdev(pd->device);
17618c2ecf20Sopenharmony_ci	int err;
17628c2ecf20Sopenharmony_ci
17638c2ecf20Sopenharmony_ci	mr->access_mode = access_mode;
17648c2ecf20Sopenharmony_ci	mr->desc_size = desc_size;
17658c2ecf20Sopenharmony_ci	mr->max_descs = ndescs;
17668c2ecf20Sopenharmony_ci
17678c2ecf20Sopenharmony_ci	err = mlx5_alloc_priv_descs(pd->device, mr, ndescs, desc_size);
17688c2ecf20Sopenharmony_ci	if (err)
17698c2ecf20Sopenharmony_ci		return err;
17708c2ecf20Sopenharmony_ci
17718c2ecf20Sopenharmony_ci	mlx5_set_umr_free_mkey(pd, in, ndescs, access_mode, page_shift);
17728c2ecf20Sopenharmony_ci
17738c2ecf20Sopenharmony_ci	err = mlx5_ib_create_mkey(dev, &mr->mmkey, in, inlen);
17748c2ecf20Sopenharmony_ci	if (err)
17758c2ecf20Sopenharmony_ci		goto err_free_descs;
17768c2ecf20Sopenharmony_ci
17778c2ecf20Sopenharmony_ci	mr->mmkey.type = MLX5_MKEY_MR;
17788c2ecf20Sopenharmony_ci	mr->ibmr.lkey = mr->mmkey.key;
17798c2ecf20Sopenharmony_ci	mr->ibmr.rkey = mr->mmkey.key;
17808c2ecf20Sopenharmony_ci
17818c2ecf20Sopenharmony_ci	return 0;
17828c2ecf20Sopenharmony_ci
17838c2ecf20Sopenharmony_cierr_free_descs:
17848c2ecf20Sopenharmony_ci	mlx5_free_priv_descs(mr);
17858c2ecf20Sopenharmony_ci	return err;
17868c2ecf20Sopenharmony_ci}
17878c2ecf20Sopenharmony_ci
17888c2ecf20Sopenharmony_cistatic struct mlx5_ib_mr *mlx5_ib_alloc_pi_mr(struct ib_pd *pd,
17898c2ecf20Sopenharmony_ci				u32 max_num_sg, u32 max_num_meta_sg,
17908c2ecf20Sopenharmony_ci				int desc_size, int access_mode)
17918c2ecf20Sopenharmony_ci{
17928c2ecf20Sopenharmony_ci	int inlen = MLX5_ST_SZ_BYTES(create_mkey_in);
17938c2ecf20Sopenharmony_ci	int ndescs = ALIGN(max_num_sg + max_num_meta_sg, 4);
17948c2ecf20Sopenharmony_ci	int page_shift = 0;
17958c2ecf20Sopenharmony_ci	struct mlx5_ib_mr *mr;
17968c2ecf20Sopenharmony_ci	u32 *in;
17978c2ecf20Sopenharmony_ci	int err;
17988c2ecf20Sopenharmony_ci
17998c2ecf20Sopenharmony_ci	mr = kzalloc(sizeof(*mr), GFP_KERNEL);
18008c2ecf20Sopenharmony_ci	if (!mr)
18018c2ecf20Sopenharmony_ci		return ERR_PTR(-ENOMEM);
18028c2ecf20Sopenharmony_ci
18038c2ecf20Sopenharmony_ci	mr->ibmr.pd = pd;
18048c2ecf20Sopenharmony_ci	mr->ibmr.device = pd->device;
18058c2ecf20Sopenharmony_ci
18068c2ecf20Sopenharmony_ci	in = kzalloc(inlen, GFP_KERNEL);
18078c2ecf20Sopenharmony_ci	if (!in) {
18088c2ecf20Sopenharmony_ci		err = -ENOMEM;
18098c2ecf20Sopenharmony_ci		goto err_free;
18108c2ecf20Sopenharmony_ci	}
18118c2ecf20Sopenharmony_ci
18128c2ecf20Sopenharmony_ci	if (access_mode == MLX5_MKC_ACCESS_MODE_MTT)
18138c2ecf20Sopenharmony_ci		page_shift = PAGE_SHIFT;
18148c2ecf20Sopenharmony_ci
18158c2ecf20Sopenharmony_ci	err = _mlx5_alloc_mkey_descs(pd, mr, ndescs, desc_size, page_shift,
18168c2ecf20Sopenharmony_ci				     access_mode, in, inlen);
18178c2ecf20Sopenharmony_ci	if (err)
18188c2ecf20Sopenharmony_ci		goto err_free_in;
18198c2ecf20Sopenharmony_ci
18208c2ecf20Sopenharmony_ci	mr->umem = NULL;
18218c2ecf20Sopenharmony_ci	kfree(in);
18228c2ecf20Sopenharmony_ci
18238c2ecf20Sopenharmony_ci	return mr;
18248c2ecf20Sopenharmony_ci
18258c2ecf20Sopenharmony_cierr_free_in:
18268c2ecf20Sopenharmony_ci	kfree(in);
18278c2ecf20Sopenharmony_cierr_free:
18288c2ecf20Sopenharmony_ci	kfree(mr);
18298c2ecf20Sopenharmony_ci	return ERR_PTR(err);
18308c2ecf20Sopenharmony_ci}
18318c2ecf20Sopenharmony_ci
18328c2ecf20Sopenharmony_cistatic int mlx5_alloc_mem_reg_descs(struct ib_pd *pd, struct mlx5_ib_mr *mr,
18338c2ecf20Sopenharmony_ci				    int ndescs, u32 *in, int inlen)
18348c2ecf20Sopenharmony_ci{
18358c2ecf20Sopenharmony_ci	return _mlx5_alloc_mkey_descs(pd, mr, ndescs, sizeof(struct mlx5_mtt),
18368c2ecf20Sopenharmony_ci				      PAGE_SHIFT, MLX5_MKC_ACCESS_MODE_MTT, in,
18378c2ecf20Sopenharmony_ci				      inlen);
18388c2ecf20Sopenharmony_ci}
18398c2ecf20Sopenharmony_ci
18408c2ecf20Sopenharmony_cistatic int mlx5_alloc_sg_gaps_descs(struct ib_pd *pd, struct mlx5_ib_mr *mr,
18418c2ecf20Sopenharmony_ci				    int ndescs, u32 *in, int inlen)
18428c2ecf20Sopenharmony_ci{
18438c2ecf20Sopenharmony_ci	return _mlx5_alloc_mkey_descs(pd, mr, ndescs, sizeof(struct mlx5_klm),
18448c2ecf20Sopenharmony_ci				      0, MLX5_MKC_ACCESS_MODE_KLMS, in, inlen);
18458c2ecf20Sopenharmony_ci}
18468c2ecf20Sopenharmony_ci
18478c2ecf20Sopenharmony_cistatic int mlx5_alloc_integrity_descs(struct ib_pd *pd, struct mlx5_ib_mr *mr,
18488c2ecf20Sopenharmony_ci				      int max_num_sg, int max_num_meta_sg,
18498c2ecf20Sopenharmony_ci				      u32 *in, int inlen)
18508c2ecf20Sopenharmony_ci{
18518c2ecf20Sopenharmony_ci	struct mlx5_ib_dev *dev = to_mdev(pd->device);
18528c2ecf20Sopenharmony_ci	u32 psv_index[2];
18538c2ecf20Sopenharmony_ci	void *mkc;
18548c2ecf20Sopenharmony_ci	int err;
18558c2ecf20Sopenharmony_ci
18568c2ecf20Sopenharmony_ci	mr->sig = kzalloc(sizeof(*mr->sig), GFP_KERNEL);
18578c2ecf20Sopenharmony_ci	if (!mr->sig)
18588c2ecf20Sopenharmony_ci		return -ENOMEM;
18598c2ecf20Sopenharmony_ci
18608c2ecf20Sopenharmony_ci	/* create mem & wire PSVs */
18618c2ecf20Sopenharmony_ci	err = mlx5_core_create_psv(dev->mdev, to_mpd(pd)->pdn, 2, psv_index);
18628c2ecf20Sopenharmony_ci	if (err)
18638c2ecf20Sopenharmony_ci		goto err_free_sig;
18648c2ecf20Sopenharmony_ci
18658c2ecf20Sopenharmony_ci	mr->sig->psv_memory.psv_idx = psv_index[0];
18668c2ecf20Sopenharmony_ci	mr->sig->psv_wire.psv_idx = psv_index[1];
18678c2ecf20Sopenharmony_ci
18688c2ecf20Sopenharmony_ci	mr->sig->sig_status_checked = true;
18698c2ecf20Sopenharmony_ci	mr->sig->sig_err_exists = false;
18708c2ecf20Sopenharmony_ci	/* Next UMR, Arm SIGERR */
18718c2ecf20Sopenharmony_ci	++mr->sig->sigerr_count;
18728c2ecf20Sopenharmony_ci	mr->klm_mr = mlx5_ib_alloc_pi_mr(pd, max_num_sg, max_num_meta_sg,
18738c2ecf20Sopenharmony_ci					 sizeof(struct mlx5_klm),
18748c2ecf20Sopenharmony_ci					 MLX5_MKC_ACCESS_MODE_KLMS);
18758c2ecf20Sopenharmony_ci	if (IS_ERR(mr->klm_mr)) {
18768c2ecf20Sopenharmony_ci		err = PTR_ERR(mr->klm_mr);
18778c2ecf20Sopenharmony_ci		goto err_destroy_psv;
18788c2ecf20Sopenharmony_ci	}
18798c2ecf20Sopenharmony_ci	mr->mtt_mr = mlx5_ib_alloc_pi_mr(pd, max_num_sg, max_num_meta_sg,
18808c2ecf20Sopenharmony_ci					 sizeof(struct mlx5_mtt),
18818c2ecf20Sopenharmony_ci					 MLX5_MKC_ACCESS_MODE_MTT);
18828c2ecf20Sopenharmony_ci	if (IS_ERR(mr->mtt_mr)) {
18838c2ecf20Sopenharmony_ci		err = PTR_ERR(mr->mtt_mr);
18848c2ecf20Sopenharmony_ci		goto err_free_klm_mr;
18858c2ecf20Sopenharmony_ci	}
18868c2ecf20Sopenharmony_ci
18878c2ecf20Sopenharmony_ci	/* Set bsf descriptors for mkey */
18888c2ecf20Sopenharmony_ci	mkc = MLX5_ADDR_OF(create_mkey_in, in, memory_key_mkey_entry);
18898c2ecf20Sopenharmony_ci	MLX5_SET(mkc, mkc, bsf_en, 1);
18908c2ecf20Sopenharmony_ci	MLX5_SET(mkc, mkc, bsf_octword_size, MLX5_MKEY_BSF_OCTO_SIZE);
18918c2ecf20Sopenharmony_ci
18928c2ecf20Sopenharmony_ci	err = _mlx5_alloc_mkey_descs(pd, mr, 4, sizeof(struct mlx5_klm), 0,
18938c2ecf20Sopenharmony_ci				     MLX5_MKC_ACCESS_MODE_KLMS, in, inlen);
18948c2ecf20Sopenharmony_ci	if (err)
18958c2ecf20Sopenharmony_ci		goto err_free_mtt_mr;
18968c2ecf20Sopenharmony_ci
18978c2ecf20Sopenharmony_ci	err = xa_err(xa_store(&dev->sig_mrs, mlx5_base_mkey(mr->mmkey.key),
18988c2ecf20Sopenharmony_ci			      mr->sig, GFP_KERNEL));
18998c2ecf20Sopenharmony_ci	if (err)
19008c2ecf20Sopenharmony_ci		goto err_free_descs;
19018c2ecf20Sopenharmony_ci	return 0;
19028c2ecf20Sopenharmony_ci
19038c2ecf20Sopenharmony_cierr_free_descs:
19048c2ecf20Sopenharmony_ci	destroy_mkey(dev, mr);
19058c2ecf20Sopenharmony_ci	mlx5_free_priv_descs(mr);
19068c2ecf20Sopenharmony_cierr_free_mtt_mr:
19078c2ecf20Sopenharmony_ci	dereg_mr(to_mdev(mr->mtt_mr->ibmr.device), mr->mtt_mr);
19088c2ecf20Sopenharmony_ci	mr->mtt_mr = NULL;
19098c2ecf20Sopenharmony_cierr_free_klm_mr:
19108c2ecf20Sopenharmony_ci	dereg_mr(to_mdev(mr->klm_mr->ibmr.device), mr->klm_mr);
19118c2ecf20Sopenharmony_ci	mr->klm_mr = NULL;
19128c2ecf20Sopenharmony_cierr_destroy_psv:
19138c2ecf20Sopenharmony_ci	if (mlx5_core_destroy_psv(dev->mdev, mr->sig->psv_memory.psv_idx))
19148c2ecf20Sopenharmony_ci		mlx5_ib_warn(dev, "failed to destroy mem psv %d\n",
19158c2ecf20Sopenharmony_ci			     mr->sig->psv_memory.psv_idx);
19168c2ecf20Sopenharmony_ci	if (mlx5_core_destroy_psv(dev->mdev, mr->sig->psv_wire.psv_idx))
19178c2ecf20Sopenharmony_ci		mlx5_ib_warn(dev, "failed to destroy wire psv %d\n",
19188c2ecf20Sopenharmony_ci			     mr->sig->psv_wire.psv_idx);
19198c2ecf20Sopenharmony_cierr_free_sig:
19208c2ecf20Sopenharmony_ci	kfree(mr->sig);
19218c2ecf20Sopenharmony_ci
19228c2ecf20Sopenharmony_ci	return err;
19238c2ecf20Sopenharmony_ci}
19248c2ecf20Sopenharmony_ci
19258c2ecf20Sopenharmony_cistatic struct ib_mr *__mlx5_ib_alloc_mr(struct ib_pd *pd,
19268c2ecf20Sopenharmony_ci					enum ib_mr_type mr_type, u32 max_num_sg,
19278c2ecf20Sopenharmony_ci					u32 max_num_meta_sg)
19288c2ecf20Sopenharmony_ci{
19298c2ecf20Sopenharmony_ci	struct mlx5_ib_dev *dev = to_mdev(pd->device);
19308c2ecf20Sopenharmony_ci	int inlen = MLX5_ST_SZ_BYTES(create_mkey_in);
19318c2ecf20Sopenharmony_ci	int ndescs = ALIGN(max_num_sg, 4);
19328c2ecf20Sopenharmony_ci	struct mlx5_ib_mr *mr;
19338c2ecf20Sopenharmony_ci	u32 *in;
19348c2ecf20Sopenharmony_ci	int err;
19358c2ecf20Sopenharmony_ci
19368c2ecf20Sopenharmony_ci	mr = kzalloc(sizeof(*mr), GFP_KERNEL);
19378c2ecf20Sopenharmony_ci	if (!mr)
19388c2ecf20Sopenharmony_ci		return ERR_PTR(-ENOMEM);
19398c2ecf20Sopenharmony_ci
19408c2ecf20Sopenharmony_ci	in = kzalloc(inlen, GFP_KERNEL);
19418c2ecf20Sopenharmony_ci	if (!in) {
19428c2ecf20Sopenharmony_ci		err = -ENOMEM;
19438c2ecf20Sopenharmony_ci		goto err_free;
19448c2ecf20Sopenharmony_ci	}
19458c2ecf20Sopenharmony_ci
19468c2ecf20Sopenharmony_ci	mr->ibmr.device = pd->device;
19478c2ecf20Sopenharmony_ci	mr->umem = NULL;
19488c2ecf20Sopenharmony_ci
19498c2ecf20Sopenharmony_ci	switch (mr_type) {
19508c2ecf20Sopenharmony_ci	case IB_MR_TYPE_MEM_REG:
19518c2ecf20Sopenharmony_ci		err = mlx5_alloc_mem_reg_descs(pd, mr, ndescs, in, inlen);
19528c2ecf20Sopenharmony_ci		break;
19538c2ecf20Sopenharmony_ci	case IB_MR_TYPE_SG_GAPS:
19548c2ecf20Sopenharmony_ci		err = mlx5_alloc_sg_gaps_descs(pd, mr, ndescs, in, inlen);
19558c2ecf20Sopenharmony_ci		break;
19568c2ecf20Sopenharmony_ci	case IB_MR_TYPE_INTEGRITY:
19578c2ecf20Sopenharmony_ci		err = mlx5_alloc_integrity_descs(pd, mr, max_num_sg,
19588c2ecf20Sopenharmony_ci						 max_num_meta_sg, in, inlen);
19598c2ecf20Sopenharmony_ci		break;
19608c2ecf20Sopenharmony_ci	default:
19618c2ecf20Sopenharmony_ci		mlx5_ib_warn(dev, "Invalid mr type %d\n", mr_type);
19628c2ecf20Sopenharmony_ci		err = -EINVAL;
19638c2ecf20Sopenharmony_ci	}
19648c2ecf20Sopenharmony_ci
19658c2ecf20Sopenharmony_ci	if (err)
19668c2ecf20Sopenharmony_ci		goto err_free_in;
19678c2ecf20Sopenharmony_ci
19688c2ecf20Sopenharmony_ci	kfree(in);
19698c2ecf20Sopenharmony_ci
19708c2ecf20Sopenharmony_ci	return &mr->ibmr;
19718c2ecf20Sopenharmony_ci
19728c2ecf20Sopenharmony_cierr_free_in:
19738c2ecf20Sopenharmony_ci	kfree(in);
19748c2ecf20Sopenharmony_cierr_free:
19758c2ecf20Sopenharmony_ci	kfree(mr);
19768c2ecf20Sopenharmony_ci	return ERR_PTR(err);
19778c2ecf20Sopenharmony_ci}
19788c2ecf20Sopenharmony_ci
19798c2ecf20Sopenharmony_cistruct ib_mr *mlx5_ib_alloc_mr(struct ib_pd *pd, enum ib_mr_type mr_type,
19808c2ecf20Sopenharmony_ci			       u32 max_num_sg)
19818c2ecf20Sopenharmony_ci{
19828c2ecf20Sopenharmony_ci	return __mlx5_ib_alloc_mr(pd, mr_type, max_num_sg, 0);
19838c2ecf20Sopenharmony_ci}
19848c2ecf20Sopenharmony_ci
19858c2ecf20Sopenharmony_cistruct ib_mr *mlx5_ib_alloc_mr_integrity(struct ib_pd *pd,
19868c2ecf20Sopenharmony_ci					 u32 max_num_sg, u32 max_num_meta_sg)
19878c2ecf20Sopenharmony_ci{
19888c2ecf20Sopenharmony_ci	return __mlx5_ib_alloc_mr(pd, IB_MR_TYPE_INTEGRITY, max_num_sg,
19898c2ecf20Sopenharmony_ci				  max_num_meta_sg);
19908c2ecf20Sopenharmony_ci}
19918c2ecf20Sopenharmony_ci
19928c2ecf20Sopenharmony_ciint mlx5_ib_alloc_mw(struct ib_mw *ibmw, struct ib_udata *udata)
19938c2ecf20Sopenharmony_ci{
19948c2ecf20Sopenharmony_ci	struct mlx5_ib_dev *dev = to_mdev(ibmw->device);
19958c2ecf20Sopenharmony_ci	int inlen = MLX5_ST_SZ_BYTES(create_mkey_in);
19968c2ecf20Sopenharmony_ci	struct mlx5_ib_mw *mw = to_mmw(ibmw);
19978c2ecf20Sopenharmony_ci	u32 *in = NULL;
19988c2ecf20Sopenharmony_ci	void *mkc;
19998c2ecf20Sopenharmony_ci	int ndescs;
20008c2ecf20Sopenharmony_ci	int err;
20018c2ecf20Sopenharmony_ci	struct mlx5_ib_alloc_mw req = {};
20028c2ecf20Sopenharmony_ci	struct {
20038c2ecf20Sopenharmony_ci		__u32	comp_mask;
20048c2ecf20Sopenharmony_ci		__u32	response_length;
20058c2ecf20Sopenharmony_ci	} resp = {};
20068c2ecf20Sopenharmony_ci
20078c2ecf20Sopenharmony_ci	err = ib_copy_from_udata(&req, udata, min(udata->inlen, sizeof(req)));
20088c2ecf20Sopenharmony_ci	if (err)
20098c2ecf20Sopenharmony_ci		return err;
20108c2ecf20Sopenharmony_ci
20118c2ecf20Sopenharmony_ci	if (req.comp_mask || req.reserved1 || req.reserved2)
20128c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
20138c2ecf20Sopenharmony_ci
20148c2ecf20Sopenharmony_ci	if (udata->inlen > sizeof(req) &&
20158c2ecf20Sopenharmony_ci	    !ib_is_udata_cleared(udata, sizeof(req),
20168c2ecf20Sopenharmony_ci				 udata->inlen - sizeof(req)))
20178c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
20188c2ecf20Sopenharmony_ci
20198c2ecf20Sopenharmony_ci	ndescs = req.num_klms ? roundup(req.num_klms, 4) : roundup(1, 4);
20208c2ecf20Sopenharmony_ci
20218c2ecf20Sopenharmony_ci	in = kzalloc(inlen, GFP_KERNEL);
20228c2ecf20Sopenharmony_ci	if (!in) {
20238c2ecf20Sopenharmony_ci		err = -ENOMEM;
20248c2ecf20Sopenharmony_ci		goto free;
20258c2ecf20Sopenharmony_ci	}
20268c2ecf20Sopenharmony_ci
20278c2ecf20Sopenharmony_ci	mkc = MLX5_ADDR_OF(create_mkey_in, in, memory_key_mkey_entry);
20288c2ecf20Sopenharmony_ci
20298c2ecf20Sopenharmony_ci	MLX5_SET(mkc, mkc, free, 1);
20308c2ecf20Sopenharmony_ci	MLX5_SET(mkc, mkc, translations_octword_size, ndescs);
20318c2ecf20Sopenharmony_ci	MLX5_SET(mkc, mkc, pd, to_mpd(ibmw->pd)->pdn);
20328c2ecf20Sopenharmony_ci	MLX5_SET(mkc, mkc, umr_en, 1);
20338c2ecf20Sopenharmony_ci	MLX5_SET(mkc, mkc, lr, 1);
20348c2ecf20Sopenharmony_ci	MLX5_SET(mkc, mkc, access_mode_1_0, MLX5_MKC_ACCESS_MODE_KLMS);
20358c2ecf20Sopenharmony_ci	MLX5_SET(mkc, mkc, en_rinval, !!((ibmw->type == IB_MW_TYPE_2)));
20368c2ecf20Sopenharmony_ci	MLX5_SET(mkc, mkc, qpn, 0xffffff);
20378c2ecf20Sopenharmony_ci
20388c2ecf20Sopenharmony_ci	err = mlx5_ib_create_mkey(dev, &mw->mmkey, in, inlen);
20398c2ecf20Sopenharmony_ci	if (err)
20408c2ecf20Sopenharmony_ci		goto free;
20418c2ecf20Sopenharmony_ci
20428c2ecf20Sopenharmony_ci	mw->mmkey.type = MLX5_MKEY_MW;
20438c2ecf20Sopenharmony_ci	ibmw->rkey = mw->mmkey.key;
20448c2ecf20Sopenharmony_ci	mw->ndescs = ndescs;
20458c2ecf20Sopenharmony_ci
20468c2ecf20Sopenharmony_ci	resp.response_length =
20478c2ecf20Sopenharmony_ci		min(offsetofend(typeof(resp), response_length), udata->outlen);
20488c2ecf20Sopenharmony_ci	if (resp.response_length) {
20498c2ecf20Sopenharmony_ci		err = ib_copy_to_udata(udata, &resp, resp.response_length);
20508c2ecf20Sopenharmony_ci		if (err)
20518c2ecf20Sopenharmony_ci			goto free_mkey;
20528c2ecf20Sopenharmony_ci	}
20538c2ecf20Sopenharmony_ci
20548c2ecf20Sopenharmony_ci	if (IS_ENABLED(CONFIG_INFINIBAND_ON_DEMAND_PAGING)) {
20558c2ecf20Sopenharmony_ci		err = xa_err(xa_store(&dev->odp_mkeys,
20568c2ecf20Sopenharmony_ci				      mlx5_base_mkey(mw->mmkey.key), &mw->mmkey,
20578c2ecf20Sopenharmony_ci				      GFP_KERNEL));
20588c2ecf20Sopenharmony_ci		if (err)
20598c2ecf20Sopenharmony_ci			goto free_mkey;
20608c2ecf20Sopenharmony_ci	}
20618c2ecf20Sopenharmony_ci
20628c2ecf20Sopenharmony_ci	kfree(in);
20638c2ecf20Sopenharmony_ci	return 0;
20648c2ecf20Sopenharmony_ci
20658c2ecf20Sopenharmony_cifree_mkey:
20668c2ecf20Sopenharmony_ci	mlx5_core_destroy_mkey(dev->mdev, &mw->mmkey);
20678c2ecf20Sopenharmony_cifree:
20688c2ecf20Sopenharmony_ci	kfree(in);
20698c2ecf20Sopenharmony_ci	return err;
20708c2ecf20Sopenharmony_ci}
20718c2ecf20Sopenharmony_ci
20728c2ecf20Sopenharmony_ciint mlx5_ib_dealloc_mw(struct ib_mw *mw)
20738c2ecf20Sopenharmony_ci{
20748c2ecf20Sopenharmony_ci	struct mlx5_ib_dev *dev = to_mdev(mw->device);
20758c2ecf20Sopenharmony_ci	struct mlx5_ib_mw *mmw = to_mmw(mw);
20768c2ecf20Sopenharmony_ci
20778c2ecf20Sopenharmony_ci	if (IS_ENABLED(CONFIG_INFINIBAND_ON_DEMAND_PAGING)) {
20788c2ecf20Sopenharmony_ci		xa_erase(&dev->odp_mkeys, mlx5_base_mkey(mmw->mmkey.key));
20798c2ecf20Sopenharmony_ci		/*
20808c2ecf20Sopenharmony_ci		 * pagefault_single_data_segment() may be accessing mmw under
20818c2ecf20Sopenharmony_ci		 * SRCU if the user bound an ODP MR to this MW.
20828c2ecf20Sopenharmony_ci		 */
20838c2ecf20Sopenharmony_ci		synchronize_srcu(&dev->odp_srcu);
20848c2ecf20Sopenharmony_ci	}
20858c2ecf20Sopenharmony_ci
20868c2ecf20Sopenharmony_ci	return mlx5_core_destroy_mkey(dev->mdev, &mmw->mmkey);
20878c2ecf20Sopenharmony_ci}
20888c2ecf20Sopenharmony_ci
20898c2ecf20Sopenharmony_ciint mlx5_ib_check_mr_status(struct ib_mr *ibmr, u32 check_mask,
20908c2ecf20Sopenharmony_ci			    struct ib_mr_status *mr_status)
20918c2ecf20Sopenharmony_ci{
20928c2ecf20Sopenharmony_ci	struct mlx5_ib_mr *mmr = to_mmr(ibmr);
20938c2ecf20Sopenharmony_ci	int ret = 0;
20948c2ecf20Sopenharmony_ci
20958c2ecf20Sopenharmony_ci	if (check_mask & ~IB_MR_CHECK_SIG_STATUS) {
20968c2ecf20Sopenharmony_ci		pr_err("Invalid status check mask\n");
20978c2ecf20Sopenharmony_ci		ret = -EINVAL;
20988c2ecf20Sopenharmony_ci		goto done;
20998c2ecf20Sopenharmony_ci	}
21008c2ecf20Sopenharmony_ci
21018c2ecf20Sopenharmony_ci	mr_status->fail_status = 0;
21028c2ecf20Sopenharmony_ci	if (check_mask & IB_MR_CHECK_SIG_STATUS) {
21038c2ecf20Sopenharmony_ci		if (!mmr->sig) {
21048c2ecf20Sopenharmony_ci			ret = -EINVAL;
21058c2ecf20Sopenharmony_ci			pr_err("signature status check requested on a non-signature enabled MR\n");
21068c2ecf20Sopenharmony_ci			goto done;
21078c2ecf20Sopenharmony_ci		}
21088c2ecf20Sopenharmony_ci
21098c2ecf20Sopenharmony_ci		mmr->sig->sig_status_checked = true;
21108c2ecf20Sopenharmony_ci		if (!mmr->sig->sig_err_exists)
21118c2ecf20Sopenharmony_ci			goto done;
21128c2ecf20Sopenharmony_ci
21138c2ecf20Sopenharmony_ci		if (ibmr->lkey == mmr->sig->err_item.key)
21148c2ecf20Sopenharmony_ci			memcpy(&mr_status->sig_err, &mmr->sig->err_item,
21158c2ecf20Sopenharmony_ci			       sizeof(mr_status->sig_err));
21168c2ecf20Sopenharmony_ci		else {
21178c2ecf20Sopenharmony_ci			mr_status->sig_err.err_type = IB_SIG_BAD_GUARD;
21188c2ecf20Sopenharmony_ci			mr_status->sig_err.sig_err_offset = 0;
21198c2ecf20Sopenharmony_ci			mr_status->sig_err.key = mmr->sig->err_item.key;
21208c2ecf20Sopenharmony_ci		}
21218c2ecf20Sopenharmony_ci
21228c2ecf20Sopenharmony_ci		mmr->sig->sig_err_exists = false;
21238c2ecf20Sopenharmony_ci		mr_status->fail_status |= IB_MR_CHECK_SIG_STATUS;
21248c2ecf20Sopenharmony_ci	}
21258c2ecf20Sopenharmony_ci
21268c2ecf20Sopenharmony_cidone:
21278c2ecf20Sopenharmony_ci	return ret;
21288c2ecf20Sopenharmony_ci}
21298c2ecf20Sopenharmony_ci
21308c2ecf20Sopenharmony_cistatic int
21318c2ecf20Sopenharmony_cimlx5_ib_map_pa_mr_sg_pi(struct ib_mr *ibmr, struct scatterlist *data_sg,
21328c2ecf20Sopenharmony_ci			int data_sg_nents, unsigned int *data_sg_offset,
21338c2ecf20Sopenharmony_ci			struct scatterlist *meta_sg, int meta_sg_nents,
21348c2ecf20Sopenharmony_ci			unsigned int *meta_sg_offset)
21358c2ecf20Sopenharmony_ci{
21368c2ecf20Sopenharmony_ci	struct mlx5_ib_mr *mr = to_mmr(ibmr);
21378c2ecf20Sopenharmony_ci	unsigned int sg_offset = 0;
21388c2ecf20Sopenharmony_ci	int n = 0;
21398c2ecf20Sopenharmony_ci
21408c2ecf20Sopenharmony_ci	mr->meta_length = 0;
21418c2ecf20Sopenharmony_ci	if (data_sg_nents == 1) {
21428c2ecf20Sopenharmony_ci		n++;
21438c2ecf20Sopenharmony_ci		mr->ndescs = 1;
21448c2ecf20Sopenharmony_ci		if (data_sg_offset)
21458c2ecf20Sopenharmony_ci			sg_offset = *data_sg_offset;
21468c2ecf20Sopenharmony_ci		mr->data_length = sg_dma_len(data_sg) - sg_offset;
21478c2ecf20Sopenharmony_ci		mr->data_iova = sg_dma_address(data_sg) + sg_offset;
21488c2ecf20Sopenharmony_ci		if (meta_sg_nents == 1) {
21498c2ecf20Sopenharmony_ci			n++;
21508c2ecf20Sopenharmony_ci			mr->meta_ndescs = 1;
21518c2ecf20Sopenharmony_ci			if (meta_sg_offset)
21528c2ecf20Sopenharmony_ci				sg_offset = *meta_sg_offset;
21538c2ecf20Sopenharmony_ci			else
21548c2ecf20Sopenharmony_ci				sg_offset = 0;
21558c2ecf20Sopenharmony_ci			mr->meta_length = sg_dma_len(meta_sg) - sg_offset;
21568c2ecf20Sopenharmony_ci			mr->pi_iova = sg_dma_address(meta_sg) + sg_offset;
21578c2ecf20Sopenharmony_ci		}
21588c2ecf20Sopenharmony_ci		ibmr->length = mr->data_length + mr->meta_length;
21598c2ecf20Sopenharmony_ci	}
21608c2ecf20Sopenharmony_ci
21618c2ecf20Sopenharmony_ci	return n;
21628c2ecf20Sopenharmony_ci}
21638c2ecf20Sopenharmony_ci
21648c2ecf20Sopenharmony_cistatic int
21658c2ecf20Sopenharmony_cimlx5_ib_sg_to_klms(struct mlx5_ib_mr *mr,
21668c2ecf20Sopenharmony_ci		   struct scatterlist *sgl,
21678c2ecf20Sopenharmony_ci		   unsigned short sg_nents,
21688c2ecf20Sopenharmony_ci		   unsigned int *sg_offset_p,
21698c2ecf20Sopenharmony_ci		   struct scatterlist *meta_sgl,
21708c2ecf20Sopenharmony_ci		   unsigned short meta_sg_nents,
21718c2ecf20Sopenharmony_ci		   unsigned int *meta_sg_offset_p)
21728c2ecf20Sopenharmony_ci{
21738c2ecf20Sopenharmony_ci	struct scatterlist *sg = sgl;
21748c2ecf20Sopenharmony_ci	struct mlx5_klm *klms = mr->descs;
21758c2ecf20Sopenharmony_ci	unsigned int sg_offset = sg_offset_p ? *sg_offset_p : 0;
21768c2ecf20Sopenharmony_ci	u32 lkey = mr->ibmr.pd->local_dma_lkey;
21778c2ecf20Sopenharmony_ci	int i, j = 0;
21788c2ecf20Sopenharmony_ci
21798c2ecf20Sopenharmony_ci	mr->ibmr.iova = sg_dma_address(sg) + sg_offset;
21808c2ecf20Sopenharmony_ci	mr->ibmr.length = 0;
21818c2ecf20Sopenharmony_ci
21828c2ecf20Sopenharmony_ci	for_each_sg(sgl, sg, sg_nents, i) {
21838c2ecf20Sopenharmony_ci		if (unlikely(i >= mr->max_descs))
21848c2ecf20Sopenharmony_ci			break;
21858c2ecf20Sopenharmony_ci		klms[i].va = cpu_to_be64(sg_dma_address(sg) + sg_offset);
21868c2ecf20Sopenharmony_ci		klms[i].bcount = cpu_to_be32(sg_dma_len(sg) - sg_offset);
21878c2ecf20Sopenharmony_ci		klms[i].key = cpu_to_be32(lkey);
21888c2ecf20Sopenharmony_ci		mr->ibmr.length += sg_dma_len(sg) - sg_offset;
21898c2ecf20Sopenharmony_ci
21908c2ecf20Sopenharmony_ci		sg_offset = 0;
21918c2ecf20Sopenharmony_ci	}
21928c2ecf20Sopenharmony_ci
21938c2ecf20Sopenharmony_ci	if (sg_offset_p)
21948c2ecf20Sopenharmony_ci		*sg_offset_p = sg_offset;
21958c2ecf20Sopenharmony_ci
21968c2ecf20Sopenharmony_ci	mr->ndescs = i;
21978c2ecf20Sopenharmony_ci	mr->data_length = mr->ibmr.length;
21988c2ecf20Sopenharmony_ci
21998c2ecf20Sopenharmony_ci	if (meta_sg_nents) {
22008c2ecf20Sopenharmony_ci		sg = meta_sgl;
22018c2ecf20Sopenharmony_ci		sg_offset = meta_sg_offset_p ? *meta_sg_offset_p : 0;
22028c2ecf20Sopenharmony_ci		for_each_sg(meta_sgl, sg, meta_sg_nents, j) {
22038c2ecf20Sopenharmony_ci			if (unlikely(i + j >= mr->max_descs))
22048c2ecf20Sopenharmony_ci				break;
22058c2ecf20Sopenharmony_ci			klms[i + j].va = cpu_to_be64(sg_dma_address(sg) +
22068c2ecf20Sopenharmony_ci						     sg_offset);
22078c2ecf20Sopenharmony_ci			klms[i + j].bcount = cpu_to_be32(sg_dma_len(sg) -
22088c2ecf20Sopenharmony_ci							 sg_offset);
22098c2ecf20Sopenharmony_ci			klms[i + j].key = cpu_to_be32(lkey);
22108c2ecf20Sopenharmony_ci			mr->ibmr.length += sg_dma_len(sg) - sg_offset;
22118c2ecf20Sopenharmony_ci
22128c2ecf20Sopenharmony_ci			sg_offset = 0;
22138c2ecf20Sopenharmony_ci		}
22148c2ecf20Sopenharmony_ci		if (meta_sg_offset_p)
22158c2ecf20Sopenharmony_ci			*meta_sg_offset_p = sg_offset;
22168c2ecf20Sopenharmony_ci
22178c2ecf20Sopenharmony_ci		mr->meta_ndescs = j;
22188c2ecf20Sopenharmony_ci		mr->meta_length = mr->ibmr.length - mr->data_length;
22198c2ecf20Sopenharmony_ci	}
22208c2ecf20Sopenharmony_ci
22218c2ecf20Sopenharmony_ci	return i + j;
22228c2ecf20Sopenharmony_ci}
22238c2ecf20Sopenharmony_ci
22248c2ecf20Sopenharmony_cistatic int mlx5_set_page(struct ib_mr *ibmr, u64 addr)
22258c2ecf20Sopenharmony_ci{
22268c2ecf20Sopenharmony_ci	struct mlx5_ib_mr *mr = to_mmr(ibmr);
22278c2ecf20Sopenharmony_ci	__be64 *descs;
22288c2ecf20Sopenharmony_ci
22298c2ecf20Sopenharmony_ci	if (unlikely(mr->ndescs == mr->max_descs))
22308c2ecf20Sopenharmony_ci		return -ENOMEM;
22318c2ecf20Sopenharmony_ci
22328c2ecf20Sopenharmony_ci	descs = mr->descs;
22338c2ecf20Sopenharmony_ci	descs[mr->ndescs++] = cpu_to_be64(addr | MLX5_EN_RD | MLX5_EN_WR);
22348c2ecf20Sopenharmony_ci
22358c2ecf20Sopenharmony_ci	return 0;
22368c2ecf20Sopenharmony_ci}
22378c2ecf20Sopenharmony_ci
22388c2ecf20Sopenharmony_cistatic int mlx5_set_page_pi(struct ib_mr *ibmr, u64 addr)
22398c2ecf20Sopenharmony_ci{
22408c2ecf20Sopenharmony_ci	struct mlx5_ib_mr *mr = to_mmr(ibmr);
22418c2ecf20Sopenharmony_ci	__be64 *descs;
22428c2ecf20Sopenharmony_ci
22438c2ecf20Sopenharmony_ci	if (unlikely(mr->ndescs + mr->meta_ndescs == mr->max_descs))
22448c2ecf20Sopenharmony_ci		return -ENOMEM;
22458c2ecf20Sopenharmony_ci
22468c2ecf20Sopenharmony_ci	descs = mr->descs;
22478c2ecf20Sopenharmony_ci	descs[mr->ndescs + mr->meta_ndescs++] =
22488c2ecf20Sopenharmony_ci		cpu_to_be64(addr | MLX5_EN_RD | MLX5_EN_WR);
22498c2ecf20Sopenharmony_ci
22508c2ecf20Sopenharmony_ci	return 0;
22518c2ecf20Sopenharmony_ci}
22528c2ecf20Sopenharmony_ci
22538c2ecf20Sopenharmony_cistatic int
22548c2ecf20Sopenharmony_cimlx5_ib_map_mtt_mr_sg_pi(struct ib_mr *ibmr, struct scatterlist *data_sg,
22558c2ecf20Sopenharmony_ci			 int data_sg_nents, unsigned int *data_sg_offset,
22568c2ecf20Sopenharmony_ci			 struct scatterlist *meta_sg, int meta_sg_nents,
22578c2ecf20Sopenharmony_ci			 unsigned int *meta_sg_offset)
22588c2ecf20Sopenharmony_ci{
22598c2ecf20Sopenharmony_ci	struct mlx5_ib_mr *mr = to_mmr(ibmr);
22608c2ecf20Sopenharmony_ci	struct mlx5_ib_mr *pi_mr = mr->mtt_mr;
22618c2ecf20Sopenharmony_ci	int n;
22628c2ecf20Sopenharmony_ci
22638c2ecf20Sopenharmony_ci	pi_mr->ndescs = 0;
22648c2ecf20Sopenharmony_ci	pi_mr->meta_ndescs = 0;
22658c2ecf20Sopenharmony_ci	pi_mr->meta_length = 0;
22668c2ecf20Sopenharmony_ci
22678c2ecf20Sopenharmony_ci	ib_dma_sync_single_for_cpu(ibmr->device, pi_mr->desc_map,
22688c2ecf20Sopenharmony_ci				   pi_mr->desc_size * pi_mr->max_descs,
22698c2ecf20Sopenharmony_ci				   DMA_TO_DEVICE);
22708c2ecf20Sopenharmony_ci
22718c2ecf20Sopenharmony_ci	pi_mr->ibmr.page_size = ibmr->page_size;
22728c2ecf20Sopenharmony_ci	n = ib_sg_to_pages(&pi_mr->ibmr, data_sg, data_sg_nents, data_sg_offset,
22738c2ecf20Sopenharmony_ci			   mlx5_set_page);
22748c2ecf20Sopenharmony_ci	if (n != data_sg_nents)
22758c2ecf20Sopenharmony_ci		return n;
22768c2ecf20Sopenharmony_ci
22778c2ecf20Sopenharmony_ci	pi_mr->data_iova = pi_mr->ibmr.iova;
22788c2ecf20Sopenharmony_ci	pi_mr->data_length = pi_mr->ibmr.length;
22798c2ecf20Sopenharmony_ci	pi_mr->ibmr.length = pi_mr->data_length;
22808c2ecf20Sopenharmony_ci	ibmr->length = pi_mr->data_length;
22818c2ecf20Sopenharmony_ci
22828c2ecf20Sopenharmony_ci	if (meta_sg_nents) {
22838c2ecf20Sopenharmony_ci		u64 page_mask = ~((u64)ibmr->page_size - 1);
22848c2ecf20Sopenharmony_ci		u64 iova = pi_mr->data_iova;
22858c2ecf20Sopenharmony_ci
22868c2ecf20Sopenharmony_ci		n += ib_sg_to_pages(&pi_mr->ibmr, meta_sg, meta_sg_nents,
22878c2ecf20Sopenharmony_ci				    meta_sg_offset, mlx5_set_page_pi);
22888c2ecf20Sopenharmony_ci
22898c2ecf20Sopenharmony_ci		pi_mr->meta_length = pi_mr->ibmr.length;
22908c2ecf20Sopenharmony_ci		/*
22918c2ecf20Sopenharmony_ci		 * PI address for the HW is the offset of the metadata address
22928c2ecf20Sopenharmony_ci		 * relative to the first data page address.
22938c2ecf20Sopenharmony_ci		 * It equals to first data page address + size of data pages +
22948c2ecf20Sopenharmony_ci		 * metadata offset at the first metadata page
22958c2ecf20Sopenharmony_ci		 */
22968c2ecf20Sopenharmony_ci		pi_mr->pi_iova = (iova & page_mask) +
22978c2ecf20Sopenharmony_ci				 pi_mr->ndescs * ibmr->page_size +
22988c2ecf20Sopenharmony_ci				 (pi_mr->ibmr.iova & ~page_mask);
22998c2ecf20Sopenharmony_ci		/*
23008c2ecf20Sopenharmony_ci		 * In order to use one MTT MR for data and metadata, we register
23018c2ecf20Sopenharmony_ci		 * also the gaps between the end of the data and the start of
23028c2ecf20Sopenharmony_ci		 * the metadata (the sig MR will verify that the HW will access
23038c2ecf20Sopenharmony_ci		 * to right addresses). This mapping is safe because we use
23048c2ecf20Sopenharmony_ci		 * internal mkey for the registration.
23058c2ecf20Sopenharmony_ci		 */
23068c2ecf20Sopenharmony_ci		pi_mr->ibmr.length = pi_mr->pi_iova + pi_mr->meta_length - iova;
23078c2ecf20Sopenharmony_ci		pi_mr->ibmr.iova = iova;
23088c2ecf20Sopenharmony_ci		ibmr->length += pi_mr->meta_length;
23098c2ecf20Sopenharmony_ci	}
23108c2ecf20Sopenharmony_ci
23118c2ecf20Sopenharmony_ci	ib_dma_sync_single_for_device(ibmr->device, pi_mr->desc_map,
23128c2ecf20Sopenharmony_ci				      pi_mr->desc_size * pi_mr->max_descs,
23138c2ecf20Sopenharmony_ci				      DMA_TO_DEVICE);
23148c2ecf20Sopenharmony_ci
23158c2ecf20Sopenharmony_ci	return n;
23168c2ecf20Sopenharmony_ci}
23178c2ecf20Sopenharmony_ci
23188c2ecf20Sopenharmony_cistatic int
23198c2ecf20Sopenharmony_cimlx5_ib_map_klm_mr_sg_pi(struct ib_mr *ibmr, struct scatterlist *data_sg,
23208c2ecf20Sopenharmony_ci			 int data_sg_nents, unsigned int *data_sg_offset,
23218c2ecf20Sopenharmony_ci			 struct scatterlist *meta_sg, int meta_sg_nents,
23228c2ecf20Sopenharmony_ci			 unsigned int *meta_sg_offset)
23238c2ecf20Sopenharmony_ci{
23248c2ecf20Sopenharmony_ci	struct mlx5_ib_mr *mr = to_mmr(ibmr);
23258c2ecf20Sopenharmony_ci	struct mlx5_ib_mr *pi_mr = mr->klm_mr;
23268c2ecf20Sopenharmony_ci	int n;
23278c2ecf20Sopenharmony_ci
23288c2ecf20Sopenharmony_ci	pi_mr->ndescs = 0;
23298c2ecf20Sopenharmony_ci	pi_mr->meta_ndescs = 0;
23308c2ecf20Sopenharmony_ci	pi_mr->meta_length = 0;
23318c2ecf20Sopenharmony_ci
23328c2ecf20Sopenharmony_ci	ib_dma_sync_single_for_cpu(ibmr->device, pi_mr->desc_map,
23338c2ecf20Sopenharmony_ci				   pi_mr->desc_size * pi_mr->max_descs,
23348c2ecf20Sopenharmony_ci				   DMA_TO_DEVICE);
23358c2ecf20Sopenharmony_ci
23368c2ecf20Sopenharmony_ci	n = mlx5_ib_sg_to_klms(pi_mr, data_sg, data_sg_nents, data_sg_offset,
23378c2ecf20Sopenharmony_ci			       meta_sg, meta_sg_nents, meta_sg_offset);
23388c2ecf20Sopenharmony_ci
23398c2ecf20Sopenharmony_ci	ib_dma_sync_single_for_device(ibmr->device, pi_mr->desc_map,
23408c2ecf20Sopenharmony_ci				      pi_mr->desc_size * pi_mr->max_descs,
23418c2ecf20Sopenharmony_ci				      DMA_TO_DEVICE);
23428c2ecf20Sopenharmony_ci
23438c2ecf20Sopenharmony_ci	/* This is zero-based memory region */
23448c2ecf20Sopenharmony_ci	pi_mr->data_iova = 0;
23458c2ecf20Sopenharmony_ci	pi_mr->ibmr.iova = 0;
23468c2ecf20Sopenharmony_ci	pi_mr->pi_iova = pi_mr->data_length;
23478c2ecf20Sopenharmony_ci	ibmr->length = pi_mr->ibmr.length;
23488c2ecf20Sopenharmony_ci
23498c2ecf20Sopenharmony_ci	return n;
23508c2ecf20Sopenharmony_ci}
23518c2ecf20Sopenharmony_ci
23528c2ecf20Sopenharmony_ciint mlx5_ib_map_mr_sg_pi(struct ib_mr *ibmr, struct scatterlist *data_sg,
23538c2ecf20Sopenharmony_ci			 int data_sg_nents, unsigned int *data_sg_offset,
23548c2ecf20Sopenharmony_ci			 struct scatterlist *meta_sg, int meta_sg_nents,
23558c2ecf20Sopenharmony_ci			 unsigned int *meta_sg_offset)
23568c2ecf20Sopenharmony_ci{
23578c2ecf20Sopenharmony_ci	struct mlx5_ib_mr *mr = to_mmr(ibmr);
23588c2ecf20Sopenharmony_ci	struct mlx5_ib_mr *pi_mr = NULL;
23598c2ecf20Sopenharmony_ci	int n;
23608c2ecf20Sopenharmony_ci
23618c2ecf20Sopenharmony_ci	WARN_ON(ibmr->type != IB_MR_TYPE_INTEGRITY);
23628c2ecf20Sopenharmony_ci
23638c2ecf20Sopenharmony_ci	mr->ndescs = 0;
23648c2ecf20Sopenharmony_ci	mr->data_length = 0;
23658c2ecf20Sopenharmony_ci	mr->data_iova = 0;
23668c2ecf20Sopenharmony_ci	mr->meta_ndescs = 0;
23678c2ecf20Sopenharmony_ci	mr->pi_iova = 0;
23688c2ecf20Sopenharmony_ci	/*
23698c2ecf20Sopenharmony_ci	 * As a performance optimization, if possible, there is no need to
23708c2ecf20Sopenharmony_ci	 * perform UMR operation to register the data/metadata buffers.
23718c2ecf20Sopenharmony_ci	 * First try to map the sg lists to PA descriptors with local_dma_lkey.
23728c2ecf20Sopenharmony_ci	 * Fallback to UMR only in case of a failure.
23738c2ecf20Sopenharmony_ci	 */
23748c2ecf20Sopenharmony_ci	n = mlx5_ib_map_pa_mr_sg_pi(ibmr, data_sg, data_sg_nents,
23758c2ecf20Sopenharmony_ci				    data_sg_offset, meta_sg, meta_sg_nents,
23768c2ecf20Sopenharmony_ci				    meta_sg_offset);
23778c2ecf20Sopenharmony_ci	if (n == data_sg_nents + meta_sg_nents)
23788c2ecf20Sopenharmony_ci		goto out;
23798c2ecf20Sopenharmony_ci	/*
23808c2ecf20Sopenharmony_ci	 * As a performance optimization, if possible, there is no need to map
23818c2ecf20Sopenharmony_ci	 * the sg lists to KLM descriptors. First try to map the sg lists to MTT
23828c2ecf20Sopenharmony_ci	 * descriptors and fallback to KLM only in case of a failure.
23838c2ecf20Sopenharmony_ci	 * It's more efficient for the HW to work with MTT descriptors
23848c2ecf20Sopenharmony_ci	 * (especially in high load).
23858c2ecf20Sopenharmony_ci	 * Use KLM (indirect access) only if it's mandatory.
23868c2ecf20Sopenharmony_ci	 */
23878c2ecf20Sopenharmony_ci	pi_mr = mr->mtt_mr;
23888c2ecf20Sopenharmony_ci	n = mlx5_ib_map_mtt_mr_sg_pi(ibmr, data_sg, data_sg_nents,
23898c2ecf20Sopenharmony_ci				     data_sg_offset, meta_sg, meta_sg_nents,
23908c2ecf20Sopenharmony_ci				     meta_sg_offset);
23918c2ecf20Sopenharmony_ci	if (n == data_sg_nents + meta_sg_nents)
23928c2ecf20Sopenharmony_ci		goto out;
23938c2ecf20Sopenharmony_ci
23948c2ecf20Sopenharmony_ci	pi_mr = mr->klm_mr;
23958c2ecf20Sopenharmony_ci	n = mlx5_ib_map_klm_mr_sg_pi(ibmr, data_sg, data_sg_nents,
23968c2ecf20Sopenharmony_ci				     data_sg_offset, meta_sg, meta_sg_nents,
23978c2ecf20Sopenharmony_ci				     meta_sg_offset);
23988c2ecf20Sopenharmony_ci	if (unlikely(n != data_sg_nents + meta_sg_nents))
23998c2ecf20Sopenharmony_ci		return -ENOMEM;
24008c2ecf20Sopenharmony_ci
24018c2ecf20Sopenharmony_ciout:
24028c2ecf20Sopenharmony_ci	/* This is zero-based memory region */
24038c2ecf20Sopenharmony_ci	ibmr->iova = 0;
24048c2ecf20Sopenharmony_ci	mr->pi_mr = pi_mr;
24058c2ecf20Sopenharmony_ci	if (pi_mr)
24068c2ecf20Sopenharmony_ci		ibmr->sig_attrs->meta_length = pi_mr->meta_length;
24078c2ecf20Sopenharmony_ci	else
24088c2ecf20Sopenharmony_ci		ibmr->sig_attrs->meta_length = mr->meta_length;
24098c2ecf20Sopenharmony_ci
24108c2ecf20Sopenharmony_ci	return 0;
24118c2ecf20Sopenharmony_ci}
24128c2ecf20Sopenharmony_ci
24138c2ecf20Sopenharmony_ciint mlx5_ib_map_mr_sg(struct ib_mr *ibmr, struct scatterlist *sg, int sg_nents,
24148c2ecf20Sopenharmony_ci		      unsigned int *sg_offset)
24158c2ecf20Sopenharmony_ci{
24168c2ecf20Sopenharmony_ci	struct mlx5_ib_mr *mr = to_mmr(ibmr);
24178c2ecf20Sopenharmony_ci	int n;
24188c2ecf20Sopenharmony_ci
24198c2ecf20Sopenharmony_ci	mr->ndescs = 0;
24208c2ecf20Sopenharmony_ci
24218c2ecf20Sopenharmony_ci	ib_dma_sync_single_for_cpu(ibmr->device, mr->desc_map,
24228c2ecf20Sopenharmony_ci				   mr->desc_size * mr->max_descs,
24238c2ecf20Sopenharmony_ci				   DMA_TO_DEVICE);
24248c2ecf20Sopenharmony_ci
24258c2ecf20Sopenharmony_ci	if (mr->access_mode == MLX5_MKC_ACCESS_MODE_KLMS)
24268c2ecf20Sopenharmony_ci		n = mlx5_ib_sg_to_klms(mr, sg, sg_nents, sg_offset, NULL, 0,
24278c2ecf20Sopenharmony_ci				       NULL);
24288c2ecf20Sopenharmony_ci	else
24298c2ecf20Sopenharmony_ci		n = ib_sg_to_pages(ibmr, sg, sg_nents, sg_offset,
24308c2ecf20Sopenharmony_ci				mlx5_set_page);
24318c2ecf20Sopenharmony_ci
24328c2ecf20Sopenharmony_ci	ib_dma_sync_single_for_device(ibmr->device, mr->desc_map,
24338c2ecf20Sopenharmony_ci				      mr->desc_size * mr->max_descs,
24348c2ecf20Sopenharmony_ci				      DMA_TO_DEVICE);
24358c2ecf20Sopenharmony_ci
24368c2ecf20Sopenharmony_ci	return n;
24378c2ecf20Sopenharmony_ci}
2438