xref: /openbmc/linux/drivers/infiniband/hw/mlx5/mr.c (revision 34d6f206a88c2651d216bd3487ac956a40b2ba8e)
1e126ba97SEli Cohen /*
26cf0a15fSSaeed Mahameed  * Copyright (c) 2013-2015, Mellanox Technologies. All rights reserved.
390da7dc8SJianxin Xiong  * Copyright (c) 2020, Intel Corporation. All rights reserved.
4e126ba97SEli Cohen  *
5e126ba97SEli Cohen  * This software is available to you under a choice of one of two
6e126ba97SEli Cohen  * licenses.  You may choose to be licensed under the terms of the GNU
7e126ba97SEli Cohen  * General Public License (GPL) Version 2, available from the file
8e126ba97SEli Cohen  * COPYING in the main directory of this source tree, or the
9e126ba97SEli Cohen  * OpenIB.org BSD license below:
10e126ba97SEli Cohen  *
11e126ba97SEli Cohen  *     Redistribution and use in source and binary forms, with or
12e126ba97SEli Cohen  *     without modification, are permitted provided that the following
13e126ba97SEli Cohen  *     conditions are met:
14e126ba97SEli Cohen  *
15e126ba97SEli Cohen  *      - Redistributions of source code must retain the above
16e126ba97SEli Cohen  *        copyright notice, this list of conditions and the following
17e126ba97SEli Cohen  *        disclaimer.
18e126ba97SEli Cohen  *
19e126ba97SEli Cohen  *      - Redistributions in binary form must reproduce the above
20e126ba97SEli Cohen  *        copyright notice, this list of conditions and the following
21e126ba97SEli Cohen  *        disclaimer in the documentation and/or other materials
22e126ba97SEli Cohen  *        provided with the distribution.
23e126ba97SEli Cohen  *
24e126ba97SEli Cohen  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
25e126ba97SEli Cohen  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
26e126ba97SEli Cohen  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
27e126ba97SEli Cohen  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
28e126ba97SEli Cohen  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
29e126ba97SEli Cohen  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
30e126ba97SEli Cohen  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
31e126ba97SEli Cohen  * SOFTWARE.
32e126ba97SEli Cohen  */
33e126ba97SEli Cohen 
34e126ba97SEli Cohen 
35e126ba97SEli Cohen #include <linux/kref.h>
36e126ba97SEli Cohen #include <linux/random.h>
37e126ba97SEli Cohen #include <linux/debugfs.h>
38e126ba97SEli Cohen #include <linux/export.h>
39746b5583SEli Cohen #include <linux/delay.h>
4090da7dc8SJianxin Xiong #include <linux/dma-buf.h>
4190da7dc8SJianxin Xiong #include <linux/dma-resv.h>
42b4cfe447SHaggai Eran #include <rdma/ib_umem_odp.h>
43831df883SMaor Gottlieb #include "dm.h"
44e126ba97SEli Cohen #include "mlx5_ib.h"
45f49c856aSAharon Landau #include "umr.h"
46e126ba97SEli Cohen 
47e126ba97SEli Cohen enum {
48746b5583SEli Cohen 	MAX_PENDING_REG_MR = 8,
49e126ba97SEli Cohen };
50e126ba97SEli Cohen 
51*613a8d27SMichael Guralnik #define MLX5_MR_CACHE_PERSISTENT_ENTRY_MIN_DESCS 4
52832a6b06SHaggai Eran #define MLX5_UMR_ALIGN 2048
53fe45f827SEli Cohen 
54fc6a9f86SSaeed Mahameed static void
55fc6a9f86SSaeed Mahameed create_mkey_callback(int status, struct mlx5_async_work *context);
56ef3642c4SJason Gunthorpe static struct mlx5_ib_mr *reg_create(struct ib_pd *pd, struct ib_umem *umem,
57ef3642c4SJason Gunthorpe 				     u64 iova, int access_flags,
58ef3642c4SJason Gunthorpe 				     unsigned int page_size, bool populate);
59fc6a9f86SSaeed Mahameed 
set_mkc_access_pd_addr_fields(void * mkc,int acc,u64 start_addr,struct ib_pd * pd)605eb29f0dSJason Gunthorpe static void set_mkc_access_pd_addr_fields(void *mkc, int acc, u64 start_addr,
615eb29f0dSJason Gunthorpe 					  struct ib_pd *pd)
625eb29f0dSJason Gunthorpe {
635eb29f0dSJason Gunthorpe 	struct mlx5_ib_dev *dev = to_mdev(pd->device);
645eb29f0dSJason Gunthorpe 
655eb29f0dSJason Gunthorpe 	MLX5_SET(mkc, mkc, a, !!(acc & IB_ACCESS_REMOTE_ATOMIC));
665eb29f0dSJason Gunthorpe 	MLX5_SET(mkc, mkc, rw, !!(acc & IB_ACCESS_REMOTE_WRITE));
675eb29f0dSJason Gunthorpe 	MLX5_SET(mkc, mkc, rr, !!(acc & IB_ACCESS_REMOTE_READ));
685eb29f0dSJason Gunthorpe 	MLX5_SET(mkc, mkc, lw, !!(acc & IB_ACCESS_LOCAL_WRITE));
695eb29f0dSJason Gunthorpe 	MLX5_SET(mkc, mkc, lr, 1);
705eb29f0dSJason Gunthorpe 
71ed4b0661SAvihai Horon 	if (acc & IB_ACCESS_RELAXED_ORDERING) {
725eb29f0dSJason Gunthorpe 		if (MLX5_CAP_GEN(dev->mdev, relaxed_ordering_write))
7377528e2aSAharon Landau 			MLX5_SET(mkc, mkc, relaxed_ordering_write, 1);
74bd4ba605SAvihai Horon 
75bd4ba605SAvihai Horon 		if (MLX5_CAP_GEN(dev->mdev, relaxed_ordering_read) ||
76bd4ba605SAvihai Horon 		    (MLX5_CAP_GEN(dev->mdev,
77ccbbfe06SAvihai Horon 				  relaxed_ordering_read_pci_enabled) &&
78bd4ba605SAvihai Horon 		     pcie_relaxed_ordering_enabled(dev->mdev->pdev)))
7977528e2aSAharon Landau 			MLX5_SET(mkc, mkc, relaxed_ordering_read, 1);
8077528e2aSAharon Landau 	}
815eb29f0dSJason Gunthorpe 
825eb29f0dSJason Gunthorpe 	MLX5_SET(mkc, mkc, pd, to_mpd(pd)->pdn);
835eb29f0dSJason Gunthorpe 	MLX5_SET(mkc, mkc, qpn, 0xffffff);
845eb29f0dSJason Gunthorpe 	MLX5_SET64(mkc, mkc, start_addr, start_addr);
855eb29f0dSJason Gunthorpe }
865eb29f0dSJason Gunthorpe 
assign_mkey_variant(struct mlx5_ib_dev * dev,u32 * mkey,u32 * in)876b753386SAharon Landau static void assign_mkey_variant(struct mlx5_ib_dev *dev, u32 *mkey, u32 *in)
88fc6a9f86SSaeed Mahameed {
89f743ff3bSSaeed Mahameed 	u8 key = atomic_inc_return(&dev->mkey_var);
90fc6a9f86SSaeed Mahameed 	void *mkc;
91fc6a9f86SSaeed Mahameed 
92fc6a9f86SSaeed Mahameed 	mkc = MLX5_ADDR_OF(create_mkey_in, in, memory_key_mkey_entry);
93fc6a9f86SSaeed Mahameed 	MLX5_SET(mkc, mkc, mkey_7_0, key);
946b753386SAharon Landau 	*mkey = key;
95fc6a9f86SSaeed Mahameed }
96fc6a9f86SSaeed Mahameed 
mlx5_ib_create_mkey(struct mlx5_ib_dev * dev,struct mlx5_ib_mkey * mkey,u32 * in,int inlen)974123bfb0SAharon Landau static int mlx5_ib_create_mkey(struct mlx5_ib_dev *dev,
984123bfb0SAharon Landau 			       struct mlx5_ib_mkey *mkey, u32 *in, int inlen)
99fc6a9f86SSaeed Mahameed {
10083fec3f1SAharon Landau 	int ret;
10183fec3f1SAharon Landau 
1026b753386SAharon Landau 	assign_mkey_variant(dev, &mkey->key, in);
10383fec3f1SAharon Landau 	ret = mlx5_core_create_mkey(dev->mdev, &mkey->key, in, inlen);
10483fec3f1SAharon Landau 	if (!ret)
10583fec3f1SAharon Landau 		init_waitqueue_head(&mkey->wait);
10683fec3f1SAharon Landau 
10783fec3f1SAharon Landau 	return ret;
108fc6a9f86SSaeed Mahameed }
109fc6a9f86SSaeed Mahameed 
mlx5_ib_create_mkey_cb(struct mlx5r_async_create_mkey * async_create)1106b753386SAharon Landau static int mlx5_ib_create_mkey_cb(struct mlx5r_async_create_mkey *async_create)
111fc6a9f86SSaeed Mahameed {
1126b753386SAharon Landau 	struct mlx5_ib_dev *dev = async_create->ent->dev;
1136b753386SAharon Landau 	size_t inlen = MLX5_ST_SZ_BYTES(create_mkey_in);
1146b753386SAharon Landau 	size_t outlen = MLX5_ST_SZ_BYTES(create_mkey_out);
1156b753386SAharon Landau 
1166b753386SAharon Landau 	MLX5_SET(create_mkey_in, async_create->in, opcode,
1176b753386SAharon Landau 		 MLX5_CMD_OP_CREATE_MKEY);
1186b753386SAharon Landau 	assign_mkey_variant(dev, &async_create->mkey, async_create->in);
1196b753386SAharon Landau 	return mlx5_cmd_exec_cb(&dev->async_ctx, async_create->in, inlen,
1206b753386SAharon Landau 				async_create->out, outlen, create_mkey_callback,
1216b753386SAharon Landau 				&async_create->cb_work);
122fc6a9f86SSaeed Mahameed }
123fc6a9f86SSaeed Mahameed 
12401137808SAharon Landau static int mkey_cache_max_order(struct mlx5_ib_dev *dev);
1251c78a21aSJason Gunthorpe static void queue_adjust_cache_locked(struct mlx5_cache_ent *ent);
126c8d75a98SMajd Dibbiny 
destroy_mkey(struct mlx5_ib_dev * dev,struct mlx5_ib_mr * mr)127b4cfe447SHaggai Eran static int destroy_mkey(struct mlx5_ib_dev *dev, struct mlx5_ib_mr *mr)
128b4cfe447SHaggai Eran {
129806b101bSJason Gunthorpe 	WARN_ON(xa_load(&dev->odp_mkeys, mlx5_base_mkey(mr->mmkey.key)));
130b4cfe447SHaggai Eran 
13183fec3f1SAharon Landau 	return mlx5_core_destroy_mkey(dev->mdev, mr->mmkey.key);
132b4cfe447SHaggai Eran }
133b4cfe447SHaggai Eran 
create_mkey_warn(struct mlx5_ib_dev * dev,int status,void * out)1340a415276SSaeed Mahameed static void create_mkey_warn(struct mlx5_ib_dev *dev, int status, void *out)
1350a415276SSaeed Mahameed {
1360a415276SSaeed Mahameed 	if (status == -ENXIO) /* core driver is not available */
1370a415276SSaeed Mahameed 		return;
1380a415276SSaeed Mahameed 
1390a415276SSaeed Mahameed 	mlx5_ib_warn(dev, "async reg mr failed. status %d\n", status);
1400a415276SSaeed Mahameed 	if (status != -EREMOTEIO) /* driver specific failure */
1410a415276SSaeed Mahameed 		return;
1420a415276SSaeed Mahameed 
1430a415276SSaeed Mahameed 	/* Failed in FW, print cmd out failure details */
1440a415276SSaeed Mahameed 	mlx5_cmd_out_err(dev->mdev, MLX5_CMD_OP_CREATE_MKEY, 0, out);
1450a415276SSaeed Mahameed }
1460a415276SSaeed Mahameed 
push_mkey_locked(struct mlx5_cache_ent * ent,bool limit_pendings,void * to_store)14762712228SMichael Guralnik static int push_mkey_locked(struct mlx5_cache_ent *ent, bool limit_pendings,
14886457a92SAharon Landau 			    void *to_store)
14986457a92SAharon Landau {
15086457a92SAharon Landau 	XA_STATE(xas, &ent->mkeys, 0);
15186457a92SAharon Landau 	void *curr;
15286457a92SAharon Landau 
15386457a92SAharon Landau 	if (limit_pendings &&
15462712228SMichael Guralnik 	    (ent->reserved - ent->stored) > MAX_PENDING_REG_MR)
15586457a92SAharon Landau 		return -EAGAIN;
15662712228SMichael Guralnik 
15786457a92SAharon Landau 	while (1) {
15886457a92SAharon Landau 		/*
15986457a92SAharon Landau 		 * This is cmpxchg (NULL, XA_ZERO_ENTRY) however this version
16086457a92SAharon Landau 		 * doesn't transparently unlock. Instead we set the xas index to
16186457a92SAharon Landau 		 * the current value of reserved every iteration.
16286457a92SAharon Landau 		 */
16386457a92SAharon Landau 		xas_set(&xas, ent->reserved);
16486457a92SAharon Landau 		curr = xas_load(&xas);
16586457a92SAharon Landau 		if (!curr) {
16686457a92SAharon Landau 			if (to_store && ent->stored == ent->reserved)
16786457a92SAharon Landau 				xas_store(&xas, to_store);
16886457a92SAharon Landau 			else
16986457a92SAharon Landau 				xas_store(&xas, XA_ZERO_ENTRY);
17086457a92SAharon Landau 			if (xas_valid(&xas)) {
17186457a92SAharon Landau 				ent->reserved++;
17286457a92SAharon Landau 				if (to_store) {
17386457a92SAharon Landau 					if (ent->stored != ent->reserved)
17486457a92SAharon Landau 						__xa_store(&ent->mkeys,
17586457a92SAharon Landau 							   ent->stored,
17686457a92SAharon Landau 							   to_store,
17786457a92SAharon Landau 							   GFP_KERNEL);
17886457a92SAharon Landau 					ent->stored++;
17986457a92SAharon Landau 					queue_adjust_cache_locked(ent);
18086457a92SAharon Landau 					WRITE_ONCE(ent->dev->cache.last_add,
18186457a92SAharon Landau 						   jiffies);
18286457a92SAharon Landau 				}
18386457a92SAharon Landau 			}
18486457a92SAharon Landau 		}
18586457a92SAharon Landau 		xa_unlock_irq(&ent->mkeys);
18686457a92SAharon Landau 
18786457a92SAharon Landau 		/*
18886457a92SAharon Landau 		 * Notice xas_nomem() must always be called as it cleans
18986457a92SAharon Landau 		 * up any cached allocation.
19086457a92SAharon Landau 		 */
19186457a92SAharon Landau 		if (!xas_nomem(&xas, GFP_KERNEL))
19286457a92SAharon Landau 			break;
19386457a92SAharon Landau 		xa_lock_irq(&ent->mkeys);
19486457a92SAharon Landau 	}
19562712228SMichael Guralnik 	xa_lock_irq(&ent->mkeys);
19686457a92SAharon Landau 	if (xas_error(&xas))
19786457a92SAharon Landau 		return xas_error(&xas);
19886457a92SAharon Landau 	if (WARN_ON(curr))
19986457a92SAharon Landau 		return -EINVAL;
20086457a92SAharon Landau 	return 0;
20186457a92SAharon Landau }
20286457a92SAharon Landau 
push_mkey(struct mlx5_cache_ent * ent,bool limit_pendings,void * to_store)20362712228SMichael Guralnik static int push_mkey(struct mlx5_cache_ent *ent, bool limit_pendings,
20462712228SMichael Guralnik 		     void *to_store)
20562712228SMichael Guralnik {
20662712228SMichael Guralnik 	int ret;
20762712228SMichael Guralnik 
20862712228SMichael Guralnik 	xa_lock_irq(&ent->mkeys);
20962712228SMichael Guralnik 	ret = push_mkey_locked(ent, limit_pendings, to_store);
21062712228SMichael Guralnik 	xa_unlock_irq(&ent->mkeys);
21162712228SMichael Guralnik 	return ret;
21262712228SMichael Guralnik }
21362712228SMichael Guralnik 
undo_push_reserve_mkey(struct mlx5_cache_ent * ent)21486457a92SAharon Landau static void undo_push_reserve_mkey(struct mlx5_cache_ent *ent)
21586457a92SAharon Landau {
21686457a92SAharon Landau 	void *old;
21786457a92SAharon Landau 
21886457a92SAharon Landau 	ent->reserved--;
21986457a92SAharon Landau 	old = __xa_erase(&ent->mkeys, ent->reserved);
22086457a92SAharon Landau 	WARN_ON(old);
22186457a92SAharon Landau }
22286457a92SAharon Landau 
push_to_reserved(struct mlx5_cache_ent * ent,u32 mkey)2236b753386SAharon Landau static void push_to_reserved(struct mlx5_cache_ent *ent, u32 mkey)
22486457a92SAharon Landau {
22586457a92SAharon Landau 	void *old;
22686457a92SAharon Landau 
2276b753386SAharon Landau 	old = __xa_store(&ent->mkeys, ent->stored, xa_mk_value(mkey), 0);
22886457a92SAharon Landau 	WARN_ON(old);
22986457a92SAharon Landau 	ent->stored++;
23086457a92SAharon Landau }
23186457a92SAharon Landau 
pop_stored_mkey(struct mlx5_cache_ent * ent)2326b753386SAharon Landau static u32 pop_stored_mkey(struct mlx5_cache_ent *ent)
23386457a92SAharon Landau {
2346b753386SAharon Landau 	void *old, *xa_mkey;
23586457a92SAharon Landau 
23686457a92SAharon Landau 	ent->stored--;
23786457a92SAharon Landau 	ent->reserved--;
23886457a92SAharon Landau 
23986457a92SAharon Landau 	if (ent->stored == ent->reserved) {
2406b753386SAharon Landau 		xa_mkey = __xa_erase(&ent->mkeys, ent->stored);
2416b753386SAharon Landau 		WARN_ON(!xa_mkey);
2426b753386SAharon Landau 		return (u32)xa_to_value(xa_mkey);
24386457a92SAharon Landau 	}
24486457a92SAharon Landau 
2456b753386SAharon Landau 	xa_mkey = __xa_store(&ent->mkeys, ent->stored, XA_ZERO_ENTRY,
24686457a92SAharon Landau 			     GFP_KERNEL);
2476b753386SAharon Landau 	WARN_ON(!xa_mkey || xa_is_err(xa_mkey));
24886457a92SAharon Landau 	old = __xa_erase(&ent->mkeys, ent->reserved);
24986457a92SAharon Landau 	WARN_ON(old);
2506b753386SAharon Landau 	return (u32)xa_to_value(xa_mkey);
25186457a92SAharon Landau }
25286457a92SAharon Landau 
create_mkey_callback(int status,struct mlx5_async_work * context)253fc6a9f86SSaeed Mahameed static void create_mkey_callback(int status, struct mlx5_async_work *context)
254746b5583SEli Cohen {
2556b753386SAharon Landau 	struct mlx5r_async_create_mkey *mkey_out =
2566b753386SAharon Landau 		container_of(context, struct mlx5r_async_create_mkey, cb_work);
2576b753386SAharon Landau 	struct mlx5_cache_ent *ent = mkey_out->ent;
258ca991a7dSMaor Gottlieb 	struct mlx5_ib_dev *dev = ent->dev;
259746b5583SEli Cohen 	unsigned long flags;
260746b5583SEli Cohen 
261746b5583SEli Cohen 	if (status) {
2626b753386SAharon Landau 		create_mkey_warn(dev, status, mkey_out->out);
2636b753386SAharon Landau 		kfree(mkey_out);
26417ae3559SAharon Landau 		xa_lock_irqsave(&ent->mkeys, flags);
26586457a92SAharon Landau 		undo_push_reserve_mkey(ent);
266b9358bdbSJason Gunthorpe 		WRITE_ONCE(dev->fill_delay, 1);
26717ae3559SAharon Landau 		xa_unlock_irqrestore(&ent->mkeys, flags);
268746b5583SEli Cohen 		mod_timer(&dev->delay_timer, jiffies + HZ);
269746b5583SEli Cohen 		return;
270746b5583SEli Cohen 	}
271746b5583SEli Cohen 
2726b753386SAharon Landau 	mkey_out->mkey |= mlx5_idx_to_mkey(
2736b753386SAharon Landau 		MLX5_GET(create_mkey_out, mkey_out->out, mkey_index));
274b9358bdbSJason Gunthorpe 	WRITE_ONCE(dev->cache.last_add, jiffies);
275746b5583SEli Cohen 
27617ae3559SAharon Landau 	xa_lock_irqsave(&ent->mkeys, flags);
2776b753386SAharon Landau 	push_to_reserved(ent, mkey_out->mkey);
2781c78a21aSJason Gunthorpe 	/* If we are doing fill_to_high_water then keep going. */
2791c78a21aSJason Gunthorpe 	queue_adjust_cache_locked(ent);
28017ae3559SAharon Landau 	xa_unlock_irqrestore(&ent->mkeys, flags);
2816b753386SAharon Landau 	kfree(mkey_out);
282746b5583SEli Cohen }
283746b5583SEli Cohen 
get_mkc_octo_size(unsigned int access_mode,unsigned int ndescs)2849ee2516cSAharon Landau static int get_mkc_octo_size(unsigned int access_mode, unsigned int ndescs)
2859ee2516cSAharon Landau {
2869ee2516cSAharon Landau 	int ret = 0;
2879ee2516cSAharon Landau 
2889ee2516cSAharon Landau 	switch (access_mode) {
2899ee2516cSAharon Landau 	case MLX5_MKC_ACCESS_MODE_MTT:
2909ee2516cSAharon Landau 		ret = DIV_ROUND_UP(ndescs, MLX5_IB_UMR_OCTOWORD /
2919ee2516cSAharon Landau 						   sizeof(struct mlx5_mtt));
2929ee2516cSAharon Landau 		break;
2939ee2516cSAharon Landau 	case MLX5_MKC_ACCESS_MODE_KSM:
2949ee2516cSAharon Landau 		ret = DIV_ROUND_UP(ndescs, MLX5_IB_UMR_OCTOWORD /
2959ee2516cSAharon Landau 						   sizeof(struct mlx5_klm));
2969ee2516cSAharon Landau 		break;
2979ee2516cSAharon Landau 	default:
2989ee2516cSAharon Landau 		WARN_ON(1);
2999ee2516cSAharon Landau 	}
3009ee2516cSAharon Landau 	return ret;
3019ee2516cSAharon Landau }
3029ee2516cSAharon Landau 
set_cache_mkc(struct mlx5_cache_ent * ent,void * mkc)3036b753386SAharon Landau static void set_cache_mkc(struct mlx5_cache_ent *ent, void *mkc)
304aad719dcSJason Gunthorpe {
3054f14c6c0SMichael Guralnik 	set_mkc_access_pd_addr_fields(mkc, ent->rb_key.access_flags, 0,
3064f14c6c0SMichael Guralnik 				      ent->dev->umrc.pd);
307aad719dcSJason Gunthorpe 	MLX5_SET(mkc, mkc, free, 1);
308aad719dcSJason Gunthorpe 	MLX5_SET(mkc, mkc, umr_en, 1);
30973d09b2fSMichael Guralnik 	MLX5_SET(mkc, mkc, access_mode_1_0, ent->rb_key.access_mode & 0x3);
31073d09b2fSMichael Guralnik 	MLX5_SET(mkc, mkc, access_mode_4_2,
31173d09b2fSMichael Guralnik 		(ent->rb_key.access_mode >> 2) & 0x7);
312cd2f5179SJason Gunthorpe 	MLX5_SET(mkc, mkc, ma_translation_mode, !!ent->rb_key.ats);
313aad719dcSJason Gunthorpe 
3149ee2516cSAharon Landau 	MLX5_SET(mkc, mkc, translations_octword_size,
31573d09b2fSMichael Guralnik 		 get_mkc_octo_size(ent->rb_key.access_mode,
31673d09b2fSMichael Guralnik 				   ent->rb_key.ndescs));
317a2a88b8eSAharon Landau 	MLX5_SET(mkc, mkc, log_page_size, PAGE_SHIFT);
318aad719dcSJason Gunthorpe }
319aad719dcSJason Gunthorpe 
320aad719dcSJason Gunthorpe /* Asynchronously schedule new MRs to be populated in the cache. */
add_keys(struct mlx5_cache_ent * ent,unsigned int num)321a1d8854aSJason Gunthorpe static int add_keys(struct mlx5_cache_ent *ent, unsigned int num)
322e126ba97SEli Cohen {
3236b753386SAharon Landau 	struct mlx5r_async_create_mkey *async_create;
324ec22eb53SSaeed Mahameed 	void *mkc;
325e126ba97SEli Cohen 	int err = 0;
326e126ba97SEli Cohen 	int i;
327e126ba97SEli Cohen 
328e126ba97SEli Cohen 	for (i = 0; i < num; i++) {
3296b753386SAharon Landau 		async_create = kzalloc(sizeof(struct mlx5r_async_create_mkey),
3306b753386SAharon Landau 				       GFP_KERNEL);
3316b753386SAharon Landau 		if (!async_create)
3326b753386SAharon Landau 			return -ENOMEM;
3336b753386SAharon Landau 		mkc = MLX5_ADDR_OF(create_mkey_in, async_create->in,
3346b753386SAharon Landau 				   memory_key_mkey_entry);
3356b753386SAharon Landau 		set_cache_mkc(ent, mkc);
3366b753386SAharon Landau 		async_create->ent = ent;
33786457a92SAharon Landau 
33886457a92SAharon Landau 		err = push_mkey(ent, true, NULL);
33986457a92SAharon Landau 		if (err)
3406b753386SAharon Landau 			goto free_async_create;
34186457a92SAharon Landau 
3426b753386SAharon Landau 		err = mlx5_ib_create_mkey_cb(async_create);
343e126ba97SEli Cohen 		if (err) {
344b91e1751SJason Gunthorpe 			mlx5_ib_warn(ent->dev, "create mkey failed %d\n", err);
34586457a92SAharon Landau 			goto err_undo_reserve;
346e126ba97SEli Cohen 		}
347e126ba97SEli Cohen 	}
348e126ba97SEli Cohen 
34986457a92SAharon Landau 	return 0;
35086457a92SAharon Landau 
35186457a92SAharon Landau err_undo_reserve:
35286457a92SAharon Landau 	xa_lock_irq(&ent->mkeys);
35386457a92SAharon Landau 	undo_push_reserve_mkey(ent);
35486457a92SAharon Landau 	xa_unlock_irq(&ent->mkeys);
3556b753386SAharon Landau free_async_create:
3566b753386SAharon Landau 	kfree(async_create);
357e126ba97SEli Cohen 	return err;
358e126ba97SEli Cohen }
359e126ba97SEli Cohen 
360aad719dcSJason Gunthorpe /* Synchronously create a MR in the cache */
create_cache_mkey(struct mlx5_cache_ent * ent,u32 * mkey)3616b753386SAharon Landau static int create_cache_mkey(struct mlx5_cache_ent *ent, u32 *mkey)
362aad719dcSJason Gunthorpe {
363aad719dcSJason Gunthorpe 	size_t inlen = MLX5_ST_SZ_BYTES(create_mkey_in);
364aad719dcSJason Gunthorpe 	void *mkc;
365aad719dcSJason Gunthorpe 	u32 *in;
366aad719dcSJason Gunthorpe 	int err;
367aad719dcSJason Gunthorpe 
368aad719dcSJason Gunthorpe 	in = kzalloc(inlen, GFP_KERNEL);
369aad719dcSJason Gunthorpe 	if (!in)
3706b753386SAharon Landau 		return -ENOMEM;
371aad719dcSJason Gunthorpe 	mkc = MLX5_ADDR_OF(create_mkey_in, in, memory_key_mkey_entry);
3726b753386SAharon Landau 	set_cache_mkc(ent, mkc);
373aad719dcSJason Gunthorpe 
3746b753386SAharon Landau 	err = mlx5_core_create_mkey(ent->dev->mdev, mkey, in, inlen);
375aad719dcSJason Gunthorpe 	if (err)
3766b753386SAharon Landau 		goto free_in;
377aad719dcSJason Gunthorpe 
378aad719dcSJason Gunthorpe 	WRITE_ONCE(ent->dev->cache.last_add, jiffies);
379aad719dcSJason Gunthorpe free_in:
380aad719dcSJason Gunthorpe 	kfree(in);
3816b753386SAharon Landau 	return err;
382aad719dcSJason Gunthorpe }
383aad719dcSJason Gunthorpe 
remove_cache_mr_locked(struct mlx5_cache_ent * ent)384b9358bdbSJason Gunthorpe static void remove_cache_mr_locked(struct mlx5_cache_ent *ent)
385e126ba97SEli Cohen {
3866b753386SAharon Landau 	u32 mkey;
387e126ba97SEli Cohen 
38817ae3559SAharon Landau 	lockdep_assert_held(&ent->mkeys.xa_lock);
38986457a92SAharon Landau 	if (!ent->stored)
390a1d8854aSJason Gunthorpe 		return;
3916b753386SAharon Landau 	mkey = pop_stored_mkey(ent);
39217ae3559SAharon Landau 	xa_unlock_irq(&ent->mkeys);
3936b753386SAharon Landau 	mlx5_core_destroy_mkey(ent->dev->mdev, mkey);
39417ae3559SAharon Landau 	xa_lock_irq(&ent->mkeys);
39565edd0e7SDaniel Jurgens }
39665edd0e7SDaniel Jurgens 
resize_available_mrs(struct mlx5_cache_ent * ent,unsigned int target,bool limit_fill)397a1d8854aSJason Gunthorpe static int resize_available_mrs(struct mlx5_cache_ent *ent, unsigned int target,
398a1d8854aSJason Gunthorpe 				bool limit_fill)
39986457a92SAharon Landau 	 __acquires(&ent->mkeys) __releases(&ent->mkeys)
400a1d8854aSJason Gunthorpe {
401a1d8854aSJason Gunthorpe 	int err;
402a1d8854aSJason Gunthorpe 
40317ae3559SAharon Landau 	lockdep_assert_held(&ent->mkeys.xa_lock);
404a1d8854aSJason Gunthorpe 
405a1d8854aSJason Gunthorpe 	while (true) {
406a1d8854aSJason Gunthorpe 		if (limit_fill)
407a1d8854aSJason Gunthorpe 			target = ent->limit * 2;
40886457a92SAharon Landau 		if (target == ent->reserved)
409a1d8854aSJason Gunthorpe 			return 0;
41086457a92SAharon Landau 		if (target > ent->reserved) {
41186457a92SAharon Landau 			u32 todo = target - ent->reserved;
412a1d8854aSJason Gunthorpe 
41317ae3559SAharon Landau 			xa_unlock_irq(&ent->mkeys);
414a1d8854aSJason Gunthorpe 			err = add_keys(ent, todo);
415a1d8854aSJason Gunthorpe 			if (err == -EAGAIN)
416a1d8854aSJason Gunthorpe 				usleep_range(3000, 5000);
41717ae3559SAharon Landau 			xa_lock_irq(&ent->mkeys);
418a1d8854aSJason Gunthorpe 			if (err) {
419a1d8854aSJason Gunthorpe 				if (err != -EAGAIN)
420a1d8854aSJason Gunthorpe 					return err;
421a1d8854aSJason Gunthorpe 			} else
422a1d8854aSJason Gunthorpe 				return 0;
423a1d8854aSJason Gunthorpe 		} else {
424b9358bdbSJason Gunthorpe 			remove_cache_mr_locked(ent);
425a1d8854aSJason Gunthorpe 		}
426e126ba97SEli Cohen 	}
427e126ba97SEli Cohen }
428e126ba97SEli Cohen 
size_write(struct file * filp,const char __user * buf,size_t count,loff_t * pos)429e126ba97SEli Cohen static ssize_t size_write(struct file *filp, const char __user *buf,
430e126ba97SEli Cohen 			  size_t count, loff_t *pos)
431e126ba97SEli Cohen {
432e126ba97SEli Cohen 	struct mlx5_cache_ent *ent = filp->private_data;
433a1d8854aSJason Gunthorpe 	u32 target;
434e126ba97SEli Cohen 	int err;
435e126ba97SEli Cohen 
436a1d8854aSJason Gunthorpe 	err = kstrtou32_from_user(buf, count, 0, &target);
437a1d8854aSJason Gunthorpe 	if (err)
438e126ba97SEli Cohen 		return err;
439746b5583SEli Cohen 
440a1d8854aSJason Gunthorpe 	/*
441a1d8854aSJason Gunthorpe 	 * Target is the new value of total_mrs the user requests, however we
44286457a92SAharon Landau 	 * cannot free MRs that are in use. Compute the target value for stored
44386457a92SAharon Landau 	 * mkeys.
444a1d8854aSJason Gunthorpe 	 */
44517ae3559SAharon Landau 	xa_lock_irq(&ent->mkeys);
44619591f13SAharon Landau 	if (target < ent->in_use) {
447a1d8854aSJason Gunthorpe 		err = -EINVAL;
448a1d8854aSJason Gunthorpe 		goto err_unlock;
449e126ba97SEli Cohen 	}
45019591f13SAharon Landau 	target = target - ent->in_use;
451a1d8854aSJason Gunthorpe 	if (target < ent->limit || target > ent->limit*2) {
452a1d8854aSJason Gunthorpe 		err = -EINVAL;
453a1d8854aSJason Gunthorpe 		goto err_unlock;
454a1d8854aSJason Gunthorpe 	}
455a1d8854aSJason Gunthorpe 	err = resize_available_mrs(ent, target, false);
456a1d8854aSJason Gunthorpe 	if (err)
457a1d8854aSJason Gunthorpe 		goto err_unlock;
45817ae3559SAharon Landau 	xa_unlock_irq(&ent->mkeys);
459e126ba97SEli Cohen 
460e126ba97SEli Cohen 	return count;
461a1d8854aSJason Gunthorpe 
462a1d8854aSJason Gunthorpe err_unlock:
46317ae3559SAharon Landau 	xa_unlock_irq(&ent->mkeys);
464a1d8854aSJason Gunthorpe 	return err;
465e126ba97SEli Cohen }
466e126ba97SEli Cohen 
size_read(struct file * filp,char __user * buf,size_t count,loff_t * pos)467e126ba97SEli Cohen static ssize_t size_read(struct file *filp, char __user *buf, size_t count,
468e126ba97SEli Cohen 			 loff_t *pos)
469e126ba97SEli Cohen {
470e126ba97SEli Cohen 	struct mlx5_cache_ent *ent = filp->private_data;
471e126ba97SEli Cohen 	char lbuf[20];
472e126ba97SEli Cohen 	int err;
473e126ba97SEli Cohen 
47419591f13SAharon Landau 	err = snprintf(lbuf, sizeof(lbuf), "%ld\n", ent->stored + ent->in_use);
475e126ba97SEli Cohen 	if (err < 0)
476e126ba97SEli Cohen 		return err;
477e126ba97SEli Cohen 
47860e6627fSJann Horn 	return simple_read_from_buffer(buf, count, pos, lbuf, err);
479e126ba97SEli Cohen }
480e126ba97SEli Cohen 
481e126ba97SEli Cohen static const struct file_operations size_fops = {
482e126ba97SEli Cohen 	.owner	= THIS_MODULE,
483e126ba97SEli Cohen 	.open	= simple_open,
484e126ba97SEli Cohen 	.write	= size_write,
485e126ba97SEli Cohen 	.read	= size_read,
486e126ba97SEli Cohen };
487e126ba97SEli Cohen 
limit_write(struct file * filp,const char __user * buf,size_t count,loff_t * pos)488e126ba97SEli Cohen static ssize_t limit_write(struct file *filp, const char __user *buf,
489e126ba97SEli Cohen 			   size_t count, loff_t *pos)
490e126ba97SEli Cohen {
491e126ba97SEli Cohen 	struct mlx5_cache_ent *ent = filp->private_data;
492e126ba97SEli Cohen 	u32 var;
493e126ba97SEli Cohen 	int err;
494e126ba97SEli Cohen 
495a1d8854aSJason Gunthorpe 	err = kstrtou32_from_user(buf, count, 0, &var);
496e126ba97SEli Cohen 	if (err)
497e126ba97SEli Cohen 		return err;
498e126ba97SEli Cohen 
499a1d8854aSJason Gunthorpe 	/*
500a1d8854aSJason Gunthorpe 	 * Upon set we immediately fill the cache to high water mark implied by
501a1d8854aSJason Gunthorpe 	 * the limit.
502a1d8854aSJason Gunthorpe 	 */
50317ae3559SAharon Landau 	xa_lock_irq(&ent->mkeys);
504a1d8854aSJason Gunthorpe 	ent->limit = var;
505a1d8854aSJason Gunthorpe 	err = resize_available_mrs(ent, 0, true);
50617ae3559SAharon Landau 	xa_unlock_irq(&ent->mkeys);
507a1d8854aSJason Gunthorpe 	if (err)
508a1d8854aSJason Gunthorpe 		return err;
509e126ba97SEli Cohen 	return count;
510e126ba97SEli Cohen }
511e126ba97SEli Cohen 
limit_read(struct file * filp,char __user * buf,size_t count,loff_t * pos)512e126ba97SEli Cohen static ssize_t limit_read(struct file *filp, char __user *buf, size_t count,
513e126ba97SEli Cohen 			  loff_t *pos)
514e126ba97SEli Cohen {
515e126ba97SEli Cohen 	struct mlx5_cache_ent *ent = filp->private_data;
516e126ba97SEli Cohen 	char lbuf[20];
517e126ba97SEli Cohen 	int err;
518e126ba97SEli Cohen 
519e126ba97SEli Cohen 	err = snprintf(lbuf, sizeof(lbuf), "%d\n", ent->limit);
520e126ba97SEli Cohen 	if (err < 0)
521e126ba97SEli Cohen 		return err;
522e126ba97SEli Cohen 
52360e6627fSJann Horn 	return simple_read_from_buffer(buf, count, pos, lbuf, err);
524e126ba97SEli Cohen }
525e126ba97SEli Cohen 
526e126ba97SEli Cohen static const struct file_operations limit_fops = {
527e126ba97SEli Cohen 	.owner	= THIS_MODULE,
528e126ba97SEli Cohen 	.open	= simple_open,
529e126ba97SEli Cohen 	.write	= limit_write,
530e126ba97SEli Cohen 	.read	= limit_read,
531e126ba97SEli Cohen };
532e126ba97SEli Cohen 
someone_adding(struct mlx5_mkey_cache * cache)53301137808SAharon Landau static bool someone_adding(struct mlx5_mkey_cache *cache)
534e126ba97SEli Cohen {
535b9584517SMichael Guralnik 	struct mlx5_cache_ent *ent;
536b9584517SMichael Guralnik 	struct rb_node *node;
537b9358bdbSJason Gunthorpe 	bool ret;
538e126ba97SEli Cohen 
539b9584517SMichael Guralnik 	mutex_lock(&cache->rb_lock);
540b9584517SMichael Guralnik 	for (node = rb_first(&cache->rb_root); node; node = rb_next(node)) {
541b9584517SMichael Guralnik 		ent = rb_entry(node, struct mlx5_cache_ent, node);
54217ae3559SAharon Landau 		xa_lock_irq(&ent->mkeys);
54386457a92SAharon Landau 		ret = ent->stored < ent->limit;
54417ae3559SAharon Landau 		xa_unlock_irq(&ent->mkeys);
545b9584517SMichael Guralnik 		if (ret) {
546b9584517SMichael Guralnik 			mutex_unlock(&cache->rb_lock);
547b9358bdbSJason Gunthorpe 			return true;
548b9358bdbSJason Gunthorpe 		}
549b9584517SMichael Guralnik 	}
550b9584517SMichael Guralnik 	mutex_unlock(&cache->rb_lock);
551b9358bdbSJason Gunthorpe 	return false;
552e126ba97SEli Cohen }
553e126ba97SEli Cohen 
554ad2d3ef4SJason Gunthorpe /*
555ad2d3ef4SJason Gunthorpe  * Check if the bucket is outside the high/low water mark and schedule an async
556ad2d3ef4SJason Gunthorpe  * update. The cache refill has hysteresis, once the low water mark is hit it is
557ad2d3ef4SJason Gunthorpe  * refilled up to the high mark.
558ad2d3ef4SJason Gunthorpe  */
queue_adjust_cache_locked(struct mlx5_cache_ent * ent)559ad2d3ef4SJason Gunthorpe static void queue_adjust_cache_locked(struct mlx5_cache_ent *ent)
560ad2d3ef4SJason Gunthorpe {
56117ae3559SAharon Landau 	lockdep_assert_held(&ent->mkeys.xa_lock);
562ad2d3ef4SJason Gunthorpe 
56362712228SMichael Guralnik 	if (ent->disabled || READ_ONCE(ent->dev->fill_delay) || ent->is_tmp)
564b9358bdbSJason Gunthorpe 		return;
56586457a92SAharon Landau 	if (ent->stored < ent->limit) {
5661c78a21aSJason Gunthorpe 		ent->fill_to_high_water = true;
567185b9826SAharon Landau 		mod_delayed_work(ent->dev->cache.wq, &ent->dwork, 0);
5681c78a21aSJason Gunthorpe 	} else if (ent->fill_to_high_water &&
56986457a92SAharon Landau 		   ent->reserved < 2 * ent->limit) {
5701c78a21aSJason Gunthorpe 		/*
5711c78a21aSJason Gunthorpe 		 * Once we start populating due to hitting a low water mark
5721c78a21aSJason Gunthorpe 		 * continue until we pass the high water mark.
5731c78a21aSJason Gunthorpe 		 */
574185b9826SAharon Landau 		mod_delayed_work(ent->dev->cache.wq, &ent->dwork, 0);
57586457a92SAharon Landau 	} else if (ent->stored == 2 * ent->limit) {
5761c78a21aSJason Gunthorpe 		ent->fill_to_high_water = false;
57786457a92SAharon Landau 	} else if (ent->stored > 2 * ent->limit) {
5781c78a21aSJason Gunthorpe 		/* Queue deletion of excess entries */
5791c78a21aSJason Gunthorpe 		ent->fill_to_high_water = false;
58086457a92SAharon Landau 		if (ent->stored != ent->reserved)
5811c78a21aSJason Gunthorpe 			queue_delayed_work(ent->dev->cache.wq, &ent->dwork,
5821c78a21aSJason Gunthorpe 					   msecs_to_jiffies(1000));
5831c78a21aSJason Gunthorpe 		else
584185b9826SAharon Landau 			mod_delayed_work(ent->dev->cache.wq, &ent->dwork, 0);
5851c78a21aSJason Gunthorpe 	}
586ad2d3ef4SJason Gunthorpe }
587ad2d3ef4SJason Gunthorpe 
__cache_work_func(struct mlx5_cache_ent * ent)588e126ba97SEli Cohen static void __cache_work_func(struct mlx5_cache_ent *ent)
589e126ba97SEli Cohen {
590e126ba97SEli Cohen 	struct mlx5_ib_dev *dev = ent->dev;
59101137808SAharon Landau 	struct mlx5_mkey_cache *cache = &dev->cache;
592746b5583SEli Cohen 	int err;
593e126ba97SEli Cohen 
59417ae3559SAharon Landau 	xa_lock_irq(&ent->mkeys);
595b9358bdbSJason Gunthorpe 	if (ent->disabled)
596b9358bdbSJason Gunthorpe 		goto out;
597e126ba97SEli Cohen 
59886457a92SAharon Landau 	if (ent->fill_to_high_water && ent->reserved < 2 * ent->limit &&
599b9358bdbSJason Gunthorpe 	    !READ_ONCE(dev->fill_delay)) {
60017ae3559SAharon Landau 		xa_unlock_irq(&ent->mkeys);
601b91e1751SJason Gunthorpe 		err = add_keys(ent, 1);
60217ae3559SAharon Landau 		xa_lock_irq(&ent->mkeys);
603b9358bdbSJason Gunthorpe 		if (ent->disabled)
604b9358bdbSJason Gunthorpe 			goto out;
605b9358bdbSJason Gunthorpe 		if (err) {
606aad719dcSJason Gunthorpe 			/*
60786457a92SAharon Landau 			 * EAGAIN only happens if there are pending MRs, so we
60886457a92SAharon Landau 			 * will be rescheduled when storing them. The only
609aad719dcSJason Gunthorpe 			 * failure path here is ENOMEM.
610aad719dcSJason Gunthorpe 			 */
611aad719dcSJason Gunthorpe 			if (err != -EAGAIN) {
612b9358bdbSJason Gunthorpe 				mlx5_ib_warn(
613b9358bdbSJason Gunthorpe 					dev,
61473d09b2fSMichael Guralnik 					"add keys command failed, err %d\n",
61573d09b2fSMichael Guralnik 					err);
616746b5583SEli Cohen 				queue_delayed_work(cache->wq, &ent->dwork,
617746b5583SEli Cohen 						   msecs_to_jiffies(1000));
618b9358bdbSJason Gunthorpe 			}
619b9358bdbSJason Gunthorpe 		}
62086457a92SAharon Landau 	} else if (ent->stored > 2 * ent->limit) {
621b9358bdbSJason Gunthorpe 		bool need_delay;
622b9358bdbSJason Gunthorpe 
623ab5cdc31SLeon Romanovsky 		/*
624a1d8854aSJason Gunthorpe 		 * The remove_cache_mr() logic is performed as garbage
625a1d8854aSJason Gunthorpe 		 * collection task. Such task is intended to be run when no
626a1d8854aSJason Gunthorpe 		 * other active processes are running.
627ab5cdc31SLeon Romanovsky 		 *
628ab5cdc31SLeon Romanovsky 		 * The need_resched() will return TRUE if there are user tasks
629ab5cdc31SLeon Romanovsky 		 * to be activated in near future.
630ab5cdc31SLeon Romanovsky 		 *
631a1d8854aSJason Gunthorpe 		 * In such case, we don't execute remove_cache_mr() and postpone
632a1d8854aSJason Gunthorpe 		 * the garbage collection work to try to run in next cycle, in
633a1d8854aSJason Gunthorpe 		 * order to free CPU resources to other tasks.
634ab5cdc31SLeon Romanovsky 		 */
63517ae3559SAharon Landau 		xa_unlock_irq(&ent->mkeys);
636b9358bdbSJason Gunthorpe 		need_delay = need_resched() || someone_adding(cache) ||
637d6793ca9SAharon Landau 			     !time_after(jiffies,
638b9358bdbSJason Gunthorpe 					 READ_ONCE(cache->last_add) + 300 * HZ);
63917ae3559SAharon Landau 		xa_lock_irq(&ent->mkeys);
640b9358bdbSJason Gunthorpe 		if (ent->disabled)
641b9358bdbSJason Gunthorpe 			goto out;
64284c2362fSAharon Landau 		if (need_delay) {
643746b5583SEli Cohen 			queue_delayed_work(cache->wq, &ent->dwork, 300 * HZ);
64484c2362fSAharon Landau 			goto out;
64584c2362fSAharon Landau 		}
646b9358bdbSJason Gunthorpe 		remove_cache_mr_locked(ent);
647b9358bdbSJason Gunthorpe 		queue_adjust_cache_locked(ent);
648e126ba97SEli Cohen 	}
649b9358bdbSJason Gunthorpe out:
65017ae3559SAharon Landau 	xa_unlock_irq(&ent->mkeys);
651e126ba97SEli Cohen }
652e126ba97SEli Cohen 
delayed_cache_work_func(struct work_struct * work)653e126ba97SEli Cohen static void delayed_cache_work_func(struct work_struct *work)
654e126ba97SEli Cohen {
655e126ba97SEli Cohen 	struct mlx5_cache_ent *ent;
656e126ba97SEli Cohen 
657e126ba97SEli Cohen 	ent = container_of(work, struct mlx5_cache_ent, dwork.work);
658e126ba97SEli Cohen 	__cache_work_func(ent);
659e126ba97SEli Cohen }
660e126ba97SEli Cohen 
cache_ent_key_cmp(struct mlx5r_cache_rb_key key1,struct mlx5r_cache_rb_key key2)66173d09b2fSMichael Guralnik static int cache_ent_key_cmp(struct mlx5r_cache_rb_key key1,
66273d09b2fSMichael Guralnik 			     struct mlx5r_cache_rb_key key2)
66373d09b2fSMichael Guralnik {
66473d09b2fSMichael Guralnik 	int res;
66573d09b2fSMichael Guralnik 
66673d09b2fSMichael Guralnik 	res = key1.ats - key2.ats;
66773d09b2fSMichael Guralnik 	if (res)
66873d09b2fSMichael Guralnik 		return res;
66973d09b2fSMichael Guralnik 
67073d09b2fSMichael Guralnik 	res = key1.access_mode - key2.access_mode;
67173d09b2fSMichael Guralnik 	if (res)
67273d09b2fSMichael Guralnik 		return res;
67373d09b2fSMichael Guralnik 
67473d09b2fSMichael Guralnik 	res = key1.access_flags - key2.access_flags;
67573d09b2fSMichael Guralnik 	if (res)
67673d09b2fSMichael Guralnik 		return res;
67773d09b2fSMichael Guralnik 
67873d09b2fSMichael Guralnik 	/*
67973d09b2fSMichael Guralnik 	 * keep ndescs the last in the compare table since the find function
68073d09b2fSMichael Guralnik 	 * searches for an exact match on all properties and only closest
68173d09b2fSMichael Guralnik 	 * match in size.
68273d09b2fSMichael Guralnik 	 */
68373d09b2fSMichael Guralnik 	return key1.ndescs - key2.ndescs;
68473d09b2fSMichael Guralnik }
68573d09b2fSMichael Guralnik 
mlx5_cache_ent_insert(struct mlx5_mkey_cache * cache,struct mlx5_cache_ent * ent)686b9584517SMichael Guralnik static int mlx5_cache_ent_insert(struct mlx5_mkey_cache *cache,
687b9584517SMichael Guralnik 				 struct mlx5_cache_ent *ent)
688b9584517SMichael Guralnik {
689b9584517SMichael Guralnik 	struct rb_node **new = &cache->rb_root.rb_node, *parent = NULL;
690b9584517SMichael Guralnik 	struct mlx5_cache_ent *cur;
69173d09b2fSMichael Guralnik 	int cmp;
692b9584517SMichael Guralnik 
693b9584517SMichael Guralnik 	/* Figure out where to put new node */
694b9584517SMichael Guralnik 	while (*new) {
695b9584517SMichael Guralnik 		cur = rb_entry(*new, struct mlx5_cache_ent, node);
696b9584517SMichael Guralnik 		parent = *new;
69773d09b2fSMichael Guralnik 		cmp = cache_ent_key_cmp(cur->rb_key, ent->rb_key);
69873d09b2fSMichael Guralnik 		if (cmp > 0)
699b9584517SMichael Guralnik 			new = &((*new)->rb_left);
70073d09b2fSMichael Guralnik 		if (cmp < 0)
701b9584517SMichael Guralnik 			new = &((*new)->rb_right);
702637a3bebSJason Gunthorpe 		if (cmp == 0)
703b9584517SMichael Guralnik 			return -EEXIST;
704b9584517SMichael Guralnik 	}
705b9584517SMichael Guralnik 
706b9584517SMichael Guralnik 	/* Add new node and rebalance tree. */
707b9584517SMichael Guralnik 	rb_link_node(&ent->node, parent, new);
708b9584517SMichael Guralnik 	rb_insert_color(&ent->node, &cache->rb_root);
709b9584517SMichael Guralnik 
710b9584517SMichael Guralnik 	return 0;
711b9584517SMichael Guralnik }
712b9584517SMichael Guralnik 
71373d09b2fSMichael Guralnik static struct mlx5_cache_ent *
mkey_cache_ent_from_rb_key(struct mlx5_ib_dev * dev,struct mlx5r_cache_rb_key rb_key)71473d09b2fSMichael Guralnik mkey_cache_ent_from_rb_key(struct mlx5_ib_dev *dev,
71573d09b2fSMichael Guralnik 			   struct mlx5r_cache_rb_key rb_key)
716b9584517SMichael Guralnik {
717b9584517SMichael Guralnik 	struct rb_node *node = dev->cache.rb_root.rb_node;
718b9584517SMichael Guralnik 	struct mlx5_cache_ent *cur, *smallest = NULL;
719*613a8d27SMichael Guralnik 	u64 ndescs_limit;
72073d09b2fSMichael Guralnik 	int cmp;
721b9584517SMichael Guralnik 
722b9584517SMichael Guralnik 	/*
723b9584517SMichael Guralnik 	 * Find the smallest ent with order >= requested_order.
724b9584517SMichael Guralnik 	 */
725b9584517SMichael Guralnik 	while (node) {
726b9584517SMichael Guralnik 		cur = rb_entry(node, struct mlx5_cache_ent, node);
72773d09b2fSMichael Guralnik 		cmp = cache_ent_key_cmp(cur->rb_key, rb_key);
72873d09b2fSMichael Guralnik 		if (cmp > 0) {
729b9584517SMichael Guralnik 			smallest = cur;
730b9584517SMichael Guralnik 			node = node->rb_left;
731b9584517SMichael Guralnik 		}
73273d09b2fSMichael Guralnik 		if (cmp < 0)
733b9584517SMichael Guralnik 			node = node->rb_right;
73473d09b2fSMichael Guralnik 		if (cmp == 0)
735b9584517SMichael Guralnik 			return cur;
736b9584517SMichael Guralnik 	}
737b9584517SMichael Guralnik 
738*613a8d27SMichael Guralnik 	/*
739*613a8d27SMichael Guralnik 	 * Limit the usage of mkeys larger than twice the required size while
740*613a8d27SMichael Guralnik 	 * also allowing the usage of smallest cache entry for small MRs.
741*613a8d27SMichael Guralnik 	 */
742*613a8d27SMichael Guralnik 	ndescs_limit = max_t(u64, rb_key.ndescs * 2,
743*613a8d27SMichael Guralnik 			     MLX5_MR_CACHE_PERSISTENT_ENTRY_MIN_DESCS);
744*613a8d27SMichael Guralnik 
74573d09b2fSMichael Guralnik 	return (smallest &&
74673d09b2fSMichael Guralnik 		smallest->rb_key.access_mode == rb_key.access_mode &&
74773d09b2fSMichael Guralnik 		smallest->rb_key.access_flags == rb_key.access_flags &&
748*613a8d27SMichael Guralnik 		smallest->rb_key.ats == rb_key.ats &&
749*613a8d27SMichael Guralnik 		smallest->rb_key.ndescs <= ndescs_limit) ?
75073d09b2fSMichael Guralnik 		       smallest :
75173d09b2fSMichael Guralnik 		       NULL;
752b9584517SMichael Guralnik }
753b9584517SMichael Guralnik 
_mlx5_mr_cache_alloc(struct mlx5_ib_dev * dev,struct mlx5_cache_ent * ent,int access_flags)75473d09b2fSMichael Guralnik static struct mlx5_ib_mr *_mlx5_mr_cache_alloc(struct mlx5_ib_dev *dev,
75556561ac6SAharon Landau 					struct mlx5_cache_ent *ent,
75656561ac6SAharon Landau 					int access_flags)
75749780d42SArtemy Kovalyov {
75849780d42SArtemy Kovalyov 	struct mlx5_ib_mr *mr;
7596b753386SAharon Landau 	int err;
76049780d42SArtemy Kovalyov 
7616b753386SAharon Landau 	mr = kzalloc(sizeof(*mr), GFP_KERNEL);
7626b753386SAharon Landau 	if (!mr)
7636b753386SAharon Landau 		return ERR_PTR(-ENOMEM);
7646b753386SAharon Landau 
76517ae3559SAharon Landau 	xa_lock_irq(&ent->mkeys);
76619591f13SAharon Landau 	ent->in_use++;
76719591f13SAharon Landau 
76886457a92SAharon Landau 	if (!ent->stored) {
7692f0e60d5SAharon Landau 		queue_adjust_cache_locked(ent);
7702f0e60d5SAharon Landau 		ent->miss++;
77117ae3559SAharon Landau 		xa_unlock_irq(&ent->mkeys);
7726b753386SAharon Landau 		err = create_cache_mkey(ent, &mr->mmkey.key);
7736b753386SAharon Landau 		if (err) {
77419591f13SAharon Landau 			xa_lock_irq(&ent->mkeys);
77519591f13SAharon Landau 			ent->in_use--;
77619591f13SAharon Landau 			xa_unlock_irq(&ent->mkeys);
7776b753386SAharon Landau 			kfree(mr);
7786b753386SAharon Landau 			return ERR_PTR(err);
77919591f13SAharon Landau 		}
78049780d42SArtemy Kovalyov 	} else {
7816b753386SAharon Landau 		mr->mmkey.key = pop_stored_mkey(ent);
782ad2d3ef4SJason Gunthorpe 		queue_adjust_cache_locked(ent);
78317ae3559SAharon Landau 		xa_unlock_irq(&ent->mkeys);
784aad719dcSJason Gunthorpe 	}
7856b753386SAharon Landau 	mr->mmkey.cache_ent = ent;
7866b753386SAharon Landau 	mr->mmkey.type = MLX5_MKEY_MR;
7876b753386SAharon Landau 	init_waitqueue_head(&mr->mmkey.wait);
78849780d42SArtemy Kovalyov 	return mr;
78949780d42SArtemy Kovalyov }
79049780d42SArtemy Kovalyov 
get_unchangeable_access_flags(struct mlx5_ib_dev * dev,int access_flags)79173d09b2fSMichael Guralnik static int get_unchangeable_access_flags(struct mlx5_ib_dev *dev,
79273d09b2fSMichael Guralnik 					 int access_flags)
793e126ba97SEli Cohen {
79473d09b2fSMichael Guralnik 	int ret = 0;
795b9584517SMichael Guralnik 
79673d09b2fSMichael Guralnik 	if ((access_flags & IB_ACCESS_REMOTE_ATOMIC) &&
79773d09b2fSMichael Guralnik 	    MLX5_CAP_GEN(dev->mdev, atomic) &&
79873d09b2fSMichael Guralnik 	    MLX5_CAP_GEN(dev->mdev, umr_modify_atomic_disabled))
79973d09b2fSMichael Guralnik 		ret |= IB_ACCESS_REMOTE_ATOMIC;
80073d09b2fSMichael Guralnik 
80173d09b2fSMichael Guralnik 	if ((access_flags & IB_ACCESS_RELAXED_ORDERING) &&
80273d09b2fSMichael Guralnik 	    MLX5_CAP_GEN(dev->mdev, relaxed_ordering_write) &&
80373d09b2fSMichael Guralnik 	    !MLX5_CAP_GEN(dev->mdev, relaxed_ordering_write_umr))
80473d09b2fSMichael Guralnik 		ret |= IB_ACCESS_RELAXED_ORDERING;
80573d09b2fSMichael Guralnik 
80673d09b2fSMichael Guralnik 	if ((access_flags & IB_ACCESS_RELAXED_ORDERING) &&
807bd4ba605SAvihai Horon 	    (MLX5_CAP_GEN(dev->mdev, relaxed_ordering_read) ||
808bd4ba605SAvihai Horon 	     MLX5_CAP_GEN(dev->mdev, relaxed_ordering_read_pci_enabled)) &&
80973d09b2fSMichael Guralnik 	    !MLX5_CAP_GEN(dev->mdev, relaxed_ordering_read_umr))
81073d09b2fSMichael Guralnik 		ret |= IB_ACCESS_RELAXED_ORDERING;
81173d09b2fSMichael Guralnik 
81273d09b2fSMichael Guralnik 	return ret;
81373d09b2fSMichael Guralnik }
81473d09b2fSMichael Guralnik 
mlx5_mr_cache_alloc(struct mlx5_ib_dev * dev,int access_flags,int access_mode,int ndescs)81573d09b2fSMichael Guralnik struct mlx5_ib_mr *mlx5_mr_cache_alloc(struct mlx5_ib_dev *dev,
81673d09b2fSMichael Guralnik 				       int access_flags, int access_mode,
81773d09b2fSMichael Guralnik 				       int ndescs)
81873d09b2fSMichael Guralnik {
81973d09b2fSMichael Guralnik 	struct mlx5r_cache_rb_key rb_key = {
82073d09b2fSMichael Guralnik 		.ndescs = ndescs,
82173d09b2fSMichael Guralnik 		.access_mode = access_mode,
82273d09b2fSMichael Guralnik 		.access_flags = get_unchangeable_access_flags(dev, access_flags)
82373d09b2fSMichael Guralnik 	};
82473d09b2fSMichael Guralnik 	struct mlx5_cache_ent *ent = mkey_cache_ent_from_rb_key(dev, rb_key);
82573d09b2fSMichael Guralnik 
82673d09b2fSMichael Guralnik 	if (!ent)
82773d09b2fSMichael Guralnik 		return ERR_PTR(-EOPNOTSUPP);
82873d09b2fSMichael Guralnik 
82973d09b2fSMichael Guralnik 	return _mlx5_mr_cache_alloc(dev, ent, access_flags);
830b9584517SMichael Guralnik }
831b9584517SMichael Guralnik 
clean_keys(struct mlx5_ib_dev * dev,struct mlx5_cache_ent * ent)832b9584517SMichael Guralnik static void clean_keys(struct mlx5_ib_dev *dev, struct mlx5_cache_ent *ent)
833b9584517SMichael Guralnik {
8346b753386SAharon Landau 	u32 mkey;
835e126ba97SEli Cohen 
8363c461911SMoshe Lazer 	cancel_delayed_work(&ent->dwork);
83717ae3559SAharon Landau 	xa_lock_irq(&ent->mkeys);
83886457a92SAharon Landau 	while (ent->stored) {
8396b753386SAharon Landau 		mkey = pop_stored_mkey(ent);
84017ae3559SAharon Landau 		xa_unlock_irq(&ent->mkeys);
8416b753386SAharon Landau 		mlx5_core_destroy_mkey(dev->mdev, mkey);
84286457a92SAharon Landau 		xa_lock_irq(&ent->mkeys);
843e126ba97SEli Cohen 	}
84486457a92SAharon Landau 	xa_unlock_irq(&ent->mkeys);
845e126ba97SEli Cohen }
846e126ba97SEli Cohen 
mlx5_mkey_cache_debugfs_cleanup(struct mlx5_ib_dev * dev)84701137808SAharon Landau static void mlx5_mkey_cache_debugfs_cleanup(struct mlx5_ib_dev *dev)
84812cc1a02SLeon Romanovsky {
8496a4d00beSMark Bloch 	if (!mlx5_debugfs_root || dev->is_rep)
85012cc1a02SLeon Romanovsky 		return;
85112cc1a02SLeon Romanovsky 
852b9584517SMichael Guralnik 	debugfs_remove_recursive(dev->cache.fs_root);
853b9584517SMichael Guralnik 	dev->cache.fs_root = NULL;
85412cc1a02SLeon Romanovsky }
85512cc1a02SLeon Romanovsky 
mlx5_mkey_cache_debugfs_add_ent(struct mlx5_ib_dev * dev,struct mlx5_cache_ent * ent)85673d09b2fSMichael Guralnik static void mlx5_mkey_cache_debugfs_add_ent(struct mlx5_ib_dev *dev,
85773d09b2fSMichael Guralnik 					    struct mlx5_cache_ent *ent)
858e126ba97SEli Cohen {
85973d09b2fSMichael Guralnik 	int order = order_base_2(ent->rb_key.ndescs);
86073eb8f03SGreg Kroah-Hartman 	struct dentry *dir;
861e126ba97SEli Cohen 
862828cf593SLeon Romanovsky 	if (!mlx5_debugfs_root || dev->is_rep)
863828cf593SLeon Romanovsky 		return;
864828cf593SLeon Romanovsky 
86573d09b2fSMichael Guralnik 	if (ent->rb_key.access_mode == MLX5_MKC_ACCESS_MODE_KSM)
86673d09b2fSMichael Guralnik 		order = MLX5_IMR_KSM_CACHE_ENTRY + 2;
867e126ba97SEli Cohen 
86873d09b2fSMichael Guralnik 	sprintf(ent->name, "%d", order);
86973d09b2fSMichael Guralnik 	dir = debugfs_create_dir(ent->name, dev->cache.fs_root);
87073eb8f03SGreg Kroah-Hartman 	debugfs_create_file("size", 0600, dir, ent, &size_fops);
87173eb8f03SGreg Kroah-Hartman 	debugfs_create_file("limit", 0600, dir, ent, &limit_fops);
87286457a92SAharon Landau 	debugfs_create_ulong("cur", 0400, dir, &ent->stored);
87373eb8f03SGreg Kroah-Hartman 	debugfs_create_u32("miss", 0600, dir, &ent->miss);
874e126ba97SEli Cohen }
87573d09b2fSMichael Guralnik 
mlx5_mkey_cache_debugfs_init(struct mlx5_ib_dev * dev)87673d09b2fSMichael Guralnik static void mlx5_mkey_cache_debugfs_init(struct mlx5_ib_dev *dev)
87773d09b2fSMichael Guralnik {
87873d09b2fSMichael Guralnik 	struct dentry *dbg_root = mlx5_debugfs_get_dev_root(dev->mdev);
87973d09b2fSMichael Guralnik 	struct mlx5_mkey_cache *cache = &dev->cache;
88073d09b2fSMichael Guralnik 
88173d09b2fSMichael Guralnik 	if (!mlx5_debugfs_root || dev->is_rep)
88273d09b2fSMichael Guralnik 		return;
88373d09b2fSMichael Guralnik 
88473d09b2fSMichael Guralnik 	cache->fs_root = debugfs_create_dir("mr_cache", dbg_root);
885e126ba97SEli Cohen }
886e126ba97SEli Cohen 
delay_time_func(struct timer_list * t)887e99e88a9SKees Cook static void delay_time_func(struct timer_list *t)
888746b5583SEli Cohen {
889e99e88a9SKees Cook 	struct mlx5_ib_dev *dev = from_timer(dev, t, delay_timer);
890746b5583SEli Cohen 
891b9358bdbSJason Gunthorpe 	WRITE_ONCE(dev->fill_delay, 0);
892746b5583SEli Cohen }
893746b5583SEli Cohen 
89462712228SMichael Guralnik struct mlx5_cache_ent *
mlx5r_cache_create_ent_locked(struct mlx5_ib_dev * dev,struct mlx5r_cache_rb_key rb_key,bool persistent_entry)89562712228SMichael Guralnik mlx5r_cache_create_ent_locked(struct mlx5_ib_dev *dev,
89673d09b2fSMichael Guralnik 			      struct mlx5r_cache_rb_key rb_key,
89773d09b2fSMichael Guralnik 			      bool persistent_entry)
898b9584517SMichael Guralnik {
899b9584517SMichael Guralnik 	struct mlx5_cache_ent *ent;
90073d09b2fSMichael Guralnik 	int order;
901b9584517SMichael Guralnik 	int ret;
902b9584517SMichael Guralnik 
903b9584517SMichael Guralnik 	ent = kzalloc(sizeof(*ent), GFP_KERNEL);
904b9584517SMichael Guralnik 	if (!ent)
905b9584517SMichael Guralnik 		return ERR_PTR(-ENOMEM);
906b9584517SMichael Guralnik 
907b9584517SMichael Guralnik 	xa_init_flags(&ent->mkeys, XA_FLAGS_LOCK_IRQ);
90873d09b2fSMichael Guralnik 	ent->rb_key = rb_key;
909b9584517SMichael Guralnik 	ent->dev = dev;
91062712228SMichael Guralnik 	ent->is_tmp = !persistent_entry;
911b9584517SMichael Guralnik 
912b9584517SMichael Guralnik 	INIT_DELAYED_WORK(&ent->dwork, delayed_cache_work_func);
913b9584517SMichael Guralnik 
914b9584517SMichael Guralnik 	ret = mlx5_cache_ent_insert(&dev->cache, ent);
915b9584517SMichael Guralnik 	if (ret) {
916b9584517SMichael Guralnik 		kfree(ent);
917b9584517SMichael Guralnik 		return ERR_PTR(ret);
918b9584517SMichael Guralnik 	}
91973d09b2fSMichael Guralnik 
92073d09b2fSMichael Guralnik 	if (persistent_entry) {
92173d09b2fSMichael Guralnik 		if (rb_key.access_mode == MLX5_MKC_ACCESS_MODE_KSM)
92273d09b2fSMichael Guralnik 			order = MLX5_IMR_KSM_CACHE_ENTRY;
92373d09b2fSMichael Guralnik 		else
92473d09b2fSMichael Guralnik 			order = order_base_2(rb_key.ndescs) - 2;
92573d09b2fSMichael Guralnik 
92673d09b2fSMichael Guralnik 		if ((dev->mdev->profile.mask & MLX5_PROF_MASK_MR_CACHE) &&
92773d09b2fSMichael Guralnik 		    !dev->is_rep && mlx5_core_is_pf(dev->mdev) &&
92873d09b2fSMichael Guralnik 		    mlx5r_umr_can_load_pas(dev, 0))
92973d09b2fSMichael Guralnik 			ent->limit = dev->mdev->profile.mr_cache[order].limit;
93073d09b2fSMichael Guralnik 		else
93173d09b2fSMichael Guralnik 			ent->limit = 0;
93273d09b2fSMichael Guralnik 
93373d09b2fSMichael Guralnik 		mlx5_mkey_cache_debugfs_add_ent(dev, ent);
93462712228SMichael Guralnik 	} else {
93562712228SMichael Guralnik 		mod_delayed_work(ent->dev->cache.wq,
93662712228SMichael Guralnik 				 &ent->dev->cache.remove_ent_dwork,
93762712228SMichael Guralnik 				 msecs_to_jiffies(30 * 1000));
93873d09b2fSMichael Guralnik 	}
93973d09b2fSMichael Guralnik 
940b9584517SMichael Guralnik 	return ent;
941b9584517SMichael Guralnik }
942b9584517SMichael Guralnik 
remove_ent_work_func(struct work_struct * work)94362712228SMichael Guralnik static void remove_ent_work_func(struct work_struct *work)
94462712228SMichael Guralnik {
94562712228SMichael Guralnik 	struct mlx5_mkey_cache *cache;
94662712228SMichael Guralnik 	struct mlx5_cache_ent *ent;
94762712228SMichael Guralnik 	struct rb_node *cur;
94862712228SMichael Guralnik 
94962712228SMichael Guralnik 	cache = container_of(work, struct mlx5_mkey_cache,
95062712228SMichael Guralnik 			     remove_ent_dwork.work);
95162712228SMichael Guralnik 	mutex_lock(&cache->rb_lock);
95262712228SMichael Guralnik 	cur = rb_last(&cache->rb_root);
95362712228SMichael Guralnik 	while (cur) {
95462712228SMichael Guralnik 		ent = rb_entry(cur, struct mlx5_cache_ent, node);
95562712228SMichael Guralnik 		cur = rb_prev(cur);
95662712228SMichael Guralnik 		mutex_unlock(&cache->rb_lock);
95762712228SMichael Guralnik 
95862712228SMichael Guralnik 		xa_lock_irq(&ent->mkeys);
95962712228SMichael Guralnik 		if (!ent->is_tmp) {
96062712228SMichael Guralnik 			xa_unlock_irq(&ent->mkeys);
96162712228SMichael Guralnik 			mutex_lock(&cache->rb_lock);
96262712228SMichael Guralnik 			continue;
96362712228SMichael Guralnik 		}
96462712228SMichael Guralnik 		xa_unlock_irq(&ent->mkeys);
96562712228SMichael Guralnik 
96662712228SMichael Guralnik 		clean_keys(ent->dev, ent);
96762712228SMichael Guralnik 		mutex_lock(&cache->rb_lock);
96862712228SMichael Guralnik 	}
96962712228SMichael Guralnik 	mutex_unlock(&cache->rb_lock);
97062712228SMichael Guralnik }
97162712228SMichael Guralnik 
mlx5_mkey_cache_init(struct mlx5_ib_dev * dev)97201137808SAharon Landau int mlx5_mkey_cache_init(struct mlx5_ib_dev *dev)
973e126ba97SEli Cohen {
97401137808SAharon Landau 	struct mlx5_mkey_cache *cache = &dev->cache;
97573d09b2fSMichael Guralnik 	struct rb_root *root = &dev->cache.rb_root;
97673d09b2fSMichael Guralnik 	struct mlx5r_cache_rb_key rb_key = {
97773d09b2fSMichael Guralnik 		.access_mode = MLX5_MKC_ACCESS_MODE_MTT,
97873d09b2fSMichael Guralnik 	};
979e126ba97SEli Cohen 	struct mlx5_cache_ent *ent;
98073d09b2fSMichael Guralnik 	struct rb_node *node;
98173d09b2fSMichael Guralnik 	int ret;
982e126ba97SEli Cohen 	int i;
983e126ba97SEli Cohen 
9846bc1a656SMoshe Lazer 	mutex_init(&dev->slow_path_mutex);
985b9584517SMichael Guralnik 	mutex_init(&dev->cache.rb_lock);
986b9584517SMichael Guralnik 	dev->cache.rb_root = RB_ROOT;
98762712228SMichael Guralnik 	INIT_DELAYED_WORK(&dev->cache.remove_ent_dwork, remove_ent_work_func);
9883c856c82SBhaktipriya Shridhar 	cache->wq = alloc_ordered_workqueue("mkey_cache", WQ_MEM_RECLAIM);
989e126ba97SEli Cohen 	if (!cache->wq) {
990e126ba97SEli Cohen 		mlx5_ib_warn(dev, "failed to create work queue\n");
991e126ba97SEli Cohen 		return -ENOMEM;
992e126ba97SEli Cohen 	}
993e126ba97SEli Cohen 
994e355477eSJason Gunthorpe 	mlx5_cmd_init_async_ctx(dev->mdev, &dev->async_ctx);
995e99e88a9SKees Cook 	timer_setup(&dev->delay_timer, delay_time_func, 0);
99673d09b2fSMichael Guralnik 	mlx5_mkey_cache_debugfs_init(dev);
99762712228SMichael Guralnik 	mutex_lock(&cache->rb_lock);
99873d09b2fSMichael Guralnik 	for (i = 0; i <= mkey_cache_max_order(dev); i++) {
999*613a8d27SMichael Guralnik 		rb_key.ndescs = MLX5_MR_CACHE_PERSISTENT_ENTRY_MIN_DESCS << i;
100062712228SMichael Guralnik 		ent = mlx5r_cache_create_ent_locked(dev, rb_key, true);
100173d09b2fSMichael Guralnik 		if (IS_ERR(ent)) {
100273d09b2fSMichael Guralnik 			ret = PTR_ERR(ent);
100373d09b2fSMichael Guralnik 			goto err;
100473d09b2fSMichael Guralnik 		}
100581713d37SArtemy Kovalyov 	}
100649780d42SArtemy Kovalyov 
100773d09b2fSMichael Guralnik 	ret = mlx5_odp_init_mkey_cache(dev);
100873d09b2fSMichael Guralnik 	if (ret)
100973d09b2fSMichael Guralnik 		goto err;
101049780d42SArtemy Kovalyov 
101162712228SMichael Guralnik 	mutex_unlock(&cache->rb_lock);
101273d09b2fSMichael Guralnik 	for (node = rb_first(root); node; node = rb_next(node)) {
101373d09b2fSMichael Guralnik 		ent = rb_entry(node, struct mlx5_cache_ent, node);
101417ae3559SAharon Landau 		xa_lock_irq(&ent->mkeys);
1015ad2d3ef4SJason Gunthorpe 		queue_adjust_cache_locked(ent);
101617ae3559SAharon Landau 		xa_unlock_irq(&ent->mkeys);
1017e126ba97SEli Cohen 	}
1018e126ba97SEli Cohen 
1019e126ba97SEli Cohen 	return 0;
102073d09b2fSMichael Guralnik 
102173d09b2fSMichael Guralnik err:
102262712228SMichael Guralnik 	mutex_unlock(&cache->rb_lock);
1023828cf593SLeon Romanovsky 	mlx5_mkey_cache_debugfs_cleanup(dev);
102473d09b2fSMichael Guralnik 	mlx5_ib_warn(dev, "failed to create mkey cache entry\n");
102573d09b2fSMichael Guralnik 	return ret;
1026e126ba97SEli Cohen }
1027e126ba97SEli Cohen 
mlx5_mkey_cache_cleanup(struct mlx5_ib_dev * dev)102885f9e38aSLeon Romanovsky void mlx5_mkey_cache_cleanup(struct mlx5_ib_dev *dev)
1029e126ba97SEli Cohen {
1030b9584517SMichael Guralnik 	struct rb_root *root = &dev->cache.rb_root;
1031b9584517SMichael Guralnik 	struct mlx5_cache_ent *ent;
1032b9584517SMichael Guralnik 	struct rb_node *node;
1033e126ba97SEli Cohen 
103432927e28SMark Bloch 	if (!dev->cache.wq)
103585f9e38aSLeon Romanovsky 		return;
103632927e28SMark Bloch 
1037b9584517SMichael Guralnik 	mutex_lock(&dev->cache.rb_lock);
103804ebb29dSMoshe Shemesh 	cancel_delayed_work(&dev->cache.remove_ent_dwork);
1039b9584517SMichael Guralnik 	for (node = rb_first(root); node; node = rb_next(node)) {
1040b9584517SMichael Guralnik 		ent = rb_entry(node, struct mlx5_cache_ent, node);
104117ae3559SAharon Landau 		xa_lock_irq(&ent->mkeys);
1042b9358bdbSJason Gunthorpe 		ent->disabled = true;
104317ae3559SAharon Landau 		xa_unlock_irq(&ent->mkeys);
104404ebb29dSMoshe Shemesh 		cancel_delayed_work(&ent->dwork);
1045b9358bdbSJason Gunthorpe 	}
1046374012b0SShay Drory 	mutex_unlock(&dev->cache.rb_lock);
1047374012b0SShay Drory 
1048374012b0SShay Drory 	/*
1049374012b0SShay Drory 	 * After all entries are disabled and will not reschedule on WQ,
1050374012b0SShay Drory 	 * flush it and all async commands.
1051374012b0SShay Drory 	 */
1052374012b0SShay Drory 	flush_workqueue(dev->cache.wq);
1053e126ba97SEli Cohen 
105401137808SAharon Landau 	mlx5_mkey_cache_debugfs_cleanup(dev);
1055e355477eSJason Gunthorpe 	mlx5_cmd_cleanup_async_ctx(&dev->async_ctx);
1056e126ba97SEli Cohen 
1057374012b0SShay Drory 	/* At this point all entries are disabled and have no concurrent work. */
1058374012b0SShay Drory 	mutex_lock(&dev->cache.rb_lock);
1059b9584517SMichael Guralnik 	node = rb_first(root);
1060b9584517SMichael Guralnik 	while (node) {
1061b9584517SMichael Guralnik 		ent = rb_entry(node, struct mlx5_cache_ent, node);
1062b9584517SMichael Guralnik 		node = rb_next(node);
1063b9584517SMichael Guralnik 		clean_keys(dev, ent);
1064b9584517SMichael Guralnik 		rb_erase(&ent->node, root);
1065b9584517SMichael Guralnik 		kfree(ent);
1066b9584517SMichael Guralnik 	}
1067b9584517SMichael Guralnik 	mutex_unlock(&dev->cache.rb_lock);
1068e126ba97SEli Cohen 
10693c461911SMoshe Lazer 	destroy_workqueue(dev->cache.wq);
1070746b5583SEli Cohen 	del_timer_sync(&dev->delay_timer);
1071e126ba97SEli Cohen }
1072e126ba97SEli Cohen 
mlx5_ib_get_dma_mr(struct ib_pd * pd,int acc)1073e126ba97SEli Cohen struct ib_mr *mlx5_ib_get_dma_mr(struct ib_pd *pd, int acc)
1074e126ba97SEli Cohen {
1075e126ba97SEli Cohen 	struct mlx5_ib_dev *dev = to_mdev(pd->device);
1076ec22eb53SSaeed Mahameed 	int inlen = MLX5_ST_SZ_BYTES(create_mkey_in);
1077e126ba97SEli Cohen 	struct mlx5_ib_mr *mr;
1078ec22eb53SSaeed Mahameed 	void *mkc;
1079ec22eb53SSaeed Mahameed 	u32 *in;
1080e126ba97SEli Cohen 	int err;
1081e126ba97SEli Cohen 
1082e126ba97SEli Cohen 	mr = kzalloc(sizeof(*mr), GFP_KERNEL);
1083e126ba97SEli Cohen 	if (!mr)
1084e126ba97SEli Cohen 		return ERR_PTR(-ENOMEM);
1085e126ba97SEli Cohen 
1086ec22eb53SSaeed Mahameed 	in = kzalloc(inlen, GFP_KERNEL);
1087e126ba97SEli Cohen 	if (!in) {
1088e126ba97SEli Cohen 		err = -ENOMEM;
1089e126ba97SEli Cohen 		goto err_free;
1090e126ba97SEli Cohen 	}
1091e126ba97SEli Cohen 
1092ec22eb53SSaeed Mahameed 	mkc = MLX5_ADDR_OF(create_mkey_in, in, memory_key_mkey_entry);
1093e126ba97SEli Cohen 
1094cdbd0d2bSAriel Levkovich 	MLX5_SET(mkc, mkc, access_mode_1_0, MLX5_MKC_ACCESS_MODE_PA);
1095ec22eb53SSaeed Mahameed 	MLX5_SET(mkc, mkc, length64, 1);
10961477d44cSAvihai Horon 	set_mkc_access_pd_addr_fields(mkc, acc | IB_ACCESS_RELAXED_ORDERING, 0,
10971477d44cSAvihai Horon 				      pd);
1098ec22eb53SSaeed Mahameed 
1099fc6a9f86SSaeed Mahameed 	err = mlx5_ib_create_mkey(dev, &mr->mmkey, in, inlen);
1100e126ba97SEli Cohen 	if (err)
1101e126ba97SEli Cohen 		goto err_in;
1102e126ba97SEli Cohen 
1103e126ba97SEli Cohen 	kfree(in);
1104aa8e08d2SArtemy Kovalyov 	mr->mmkey.type = MLX5_MKEY_MR;
1105a606b0f6SMatan Barak 	mr->ibmr.lkey = mr->mmkey.key;
1106a606b0f6SMatan Barak 	mr->ibmr.rkey = mr->mmkey.key;
1107e126ba97SEli Cohen 	mr->umem = NULL;
1108e126ba97SEli Cohen 
1109e126ba97SEli Cohen 	return &mr->ibmr;
1110e126ba97SEli Cohen 
1111e126ba97SEli Cohen err_in:
1112e126ba97SEli Cohen 	kfree(in);
1113e126ba97SEli Cohen 
1114e126ba97SEli Cohen err_free:
1115e126ba97SEli Cohen 	kfree(mr);
1116e126ba97SEli Cohen 
1117e126ba97SEli Cohen 	return ERR_PTR(err);
1118e126ba97SEli Cohen }
1119e126ba97SEli Cohen 
get_octo_len(u64 addr,u64 len,int page_shift)11207b4cdaaeSIlya Lesokhin static int get_octo_len(u64 addr, u64 len, int page_shift)
1121e126ba97SEli Cohen {
11227b4cdaaeSIlya Lesokhin 	u64 page_size = 1ULL << page_shift;
1123e126ba97SEli Cohen 	u64 offset;
1124e126ba97SEli Cohen 	int npages;
1125e126ba97SEli Cohen 
1126e126ba97SEli Cohen 	offset = addr & (page_size - 1);
11277b4cdaaeSIlya Lesokhin 	npages = ALIGN(len + offset, page_size) >> page_shift;
1128e126ba97SEli Cohen 	return (npages + 1) / 2;
1129e126ba97SEli Cohen }
1130e126ba97SEli Cohen 
mkey_cache_max_order(struct mlx5_ib_dev * dev)113101137808SAharon Landau static int mkey_cache_max_order(struct mlx5_ib_dev *dev)
1132e126ba97SEli Cohen {
11337d0cc6edSArtemy Kovalyov 	if (MLX5_CAP_GEN(dev->mdev, umr_extended_translation_offset))
113473d09b2fSMichael Guralnik 		return MKEY_CACHE_LAST_STD_ENTRY;
11354c25b7a3SMajd Dibbiny 	return MLX5_MAX_UMR_SHIFT;
11364c25b7a3SMajd Dibbiny }
11374c25b7a3SMajd Dibbiny 
set_mr_fields(struct mlx5_ib_dev * dev,struct mlx5_ib_mr * mr,u64 length,int access_flags,u64 iova)113838f8ff5bSJason Gunthorpe static void set_mr_fields(struct mlx5_ib_dev *dev, struct mlx5_ib_mr *mr,
1139cf6a8b1bSAharon Landau 			  u64 length, int access_flags, u64 iova)
114038f8ff5bSJason Gunthorpe {
114138f8ff5bSJason Gunthorpe 	mr->ibmr.lkey = mr->mmkey.key;
114238f8ff5bSJason Gunthorpe 	mr->ibmr.rkey = mr->mmkey.key;
114338f8ff5bSJason Gunthorpe 	mr->ibmr.length = length;
1144ca991a7dSMaor Gottlieb 	mr->ibmr.device = &dev->ib_dev;
1145cf6a8b1bSAharon Landau 	mr->ibmr.iova = iova;
114638f8ff5bSJason Gunthorpe 	mr->access_flags = access_flags;
114738f8ff5bSJason Gunthorpe }
114838f8ff5bSJason Gunthorpe 
mlx5_umem_dmabuf_default_pgsz(struct ib_umem * umem,u64 iova)114990da7dc8SJianxin Xiong static unsigned int mlx5_umem_dmabuf_default_pgsz(struct ib_umem *umem,
115090da7dc8SJianxin Xiong 						  u64 iova)
115190da7dc8SJianxin Xiong {
115290da7dc8SJianxin Xiong 	/*
115390da7dc8SJianxin Xiong 	 * The alignment of iova has already been checked upon entering
115490da7dc8SJianxin Xiong 	 * UVERBS_METHOD_REG_DMABUF_MR
115590da7dc8SJianxin Xiong 	 */
115690da7dc8SJianxin Xiong 	umem->iova = iova;
115790da7dc8SJianxin Xiong 	return PAGE_SIZE;
115890da7dc8SJianxin Xiong }
115990da7dc8SJianxin Xiong 
alloc_cacheable_mr(struct ib_pd * pd,struct ib_umem * umem,u64 iova,int access_flags)116038f8ff5bSJason Gunthorpe static struct mlx5_ib_mr *alloc_cacheable_mr(struct ib_pd *pd,
1161f0093fb1SJason Gunthorpe 					     struct ib_umem *umem, u64 iova,
1162b91e1751SJason Gunthorpe 					     int access_flags)
1163e126ba97SEli Cohen {
116473d09b2fSMichael Guralnik 	struct mlx5r_cache_rb_key rb_key = {
116573d09b2fSMichael Guralnik 		.access_mode = MLX5_MKC_ACCESS_MODE_MTT,
116673d09b2fSMichael Guralnik 	};
1167e126ba97SEli Cohen 	struct mlx5_ib_dev *dev = to_mdev(pd->device);
1168f0093fb1SJason Gunthorpe 	struct mlx5_cache_ent *ent;
1169e126ba97SEli Cohen 	struct mlx5_ib_mr *mr;
1170d5c7916fSJason Gunthorpe 	unsigned int page_size;
1171e126ba97SEli Cohen 
117290da7dc8SJianxin Xiong 	if (umem->is_dmabuf)
117390da7dc8SJianxin Xiong 		page_size = mlx5_umem_dmabuf_default_pgsz(umem, iova);
117490da7dc8SJianxin Xiong 	else
117590da7dc8SJianxin Xiong 		page_size = mlx5_umem_find_best_pgsz(umem, mkc, log_page_size,
117690da7dc8SJianxin Xiong 						     0, iova);
1177d5c7916fSJason Gunthorpe 	if (WARN_ON(!page_size))
1178d5c7916fSJason Gunthorpe 		return ERR_PTR(-EINVAL);
117973d09b2fSMichael Guralnik 
118073d09b2fSMichael Guralnik 	rb_key.ndescs = ib_umem_num_dma_blocks(umem, page_size);
118173d09b2fSMichael Guralnik 	rb_key.ats = mlx5_umem_needs_ats(dev, umem, access_flags);
118273d09b2fSMichael Guralnik 	rb_key.access_flags = get_unchangeable_access_flags(dev, access_flags);
118373d09b2fSMichael Guralnik 	ent = mkey_cache_ent_from_rb_key(dev, rb_key);
118438f8ff5bSJason Gunthorpe 	/*
1185dd1b913fSMichael Guralnik 	 * If the MR can't come from the cache then synchronously create an uncached
1186dd1b913fSMichael Guralnik 	 * one.
118738f8ff5bSJason Gunthorpe 	 */
1188dd1b913fSMichael Guralnik 	if (!ent) {
118938f8ff5bSJason Gunthorpe 		mutex_lock(&dev->slow_path_mutex);
1190ef3642c4SJason Gunthorpe 		mr = reg_create(pd, umem, iova, access_flags, page_size, false);
119138f8ff5bSJason Gunthorpe 		mutex_unlock(&dev->slow_path_mutex);
11928e6e49ccSDan Carpenter 		if (IS_ERR(mr))
11938e6e49ccSDan Carpenter 			return mr;
1194dd1b913fSMichael Guralnik 		mr->mmkey.rb_key = rb_key;
119538f8ff5bSJason Gunthorpe 		return mr;
119638f8ff5bSJason Gunthorpe 	}
11978383da3eSJason Gunthorpe 
119873d09b2fSMichael Guralnik 	mr = _mlx5_mr_cache_alloc(dev, ent, access_flags);
1199aad719dcSJason Gunthorpe 	if (IS_ERR(mr))
1200aad719dcSJason Gunthorpe 		return mr;
1201e126ba97SEli Cohen 
12027d0cc6edSArtemy Kovalyov 	mr->ibmr.pd = pd;
12037d0cc6edSArtemy Kovalyov 	mr->umem = umem;
1204d5c7916fSJason Gunthorpe 	mr->page_shift = order_base_2(page_size);
1205cf6a8b1bSAharon Landau 	set_mr_fields(dev, mr, umem->length, access_flags, iova);
1206b475598aSHaggai Eran 
1207e126ba97SEli Cohen 	return mr;
1208e126ba97SEli Cohen }
1209e126ba97SEli Cohen 
12108010d74bSJason Gunthorpe /*
1211395a8e4cSNoa Osherovich  * If ibmr is NULL it will be allocated by reg_create.
1212395a8e4cSNoa Osherovich  * Else, the given ibmr will be used.
1213395a8e4cSNoa Osherovich  */
reg_create(struct ib_pd * pd,struct ib_umem * umem,u64 iova,int access_flags,unsigned int page_size,bool populate)1214ef3642c4SJason Gunthorpe static struct mlx5_ib_mr *reg_create(struct ib_pd *pd, struct ib_umem *umem,
1215ef3642c4SJason Gunthorpe 				     u64 iova, int access_flags,
1216ef3642c4SJason Gunthorpe 				     unsigned int page_size, bool populate)
1217e126ba97SEli Cohen {
1218e126ba97SEli Cohen 	struct mlx5_ib_dev *dev = to_mdev(pd->device);
1219e126ba97SEli Cohen 	struct mlx5_ib_mr *mr;
1220ec22eb53SSaeed Mahameed 	__be64 *pas;
1221ec22eb53SSaeed Mahameed 	void *mkc;
1222e126ba97SEli Cohen 	int inlen;
1223ec22eb53SSaeed Mahameed 	u32 *in;
1224e126ba97SEli Cohen 	int err;
1225938fe83cSSaeed Mahameed 	bool pg_cap = !!(MLX5_CAP_GEN(dev->mdev, pg));
1226e126ba97SEli Cohen 
122738f8ff5bSJason Gunthorpe 	if (!page_size)
1228d5c7916fSJason Gunthorpe 		return ERR_PTR(-EINVAL);
1229ef3642c4SJason Gunthorpe 	mr = kzalloc(sizeof(*mr), GFP_KERNEL);
1230e126ba97SEli Cohen 	if (!mr)
1231e126ba97SEli Cohen 		return ERR_PTR(-ENOMEM);
1232e126ba97SEli Cohen 
1233ff740aefSIlya Lesokhin 	mr->ibmr.pd = pd;
1234ff740aefSIlya Lesokhin 	mr->access_flags = access_flags;
1235d5c7916fSJason Gunthorpe 	mr->page_shift = order_base_2(page_size);
1236ff740aefSIlya Lesokhin 
1237ff740aefSIlya Lesokhin 	inlen = MLX5_ST_SZ_BYTES(create_mkey_in);
1238ff740aefSIlya Lesokhin 	if (populate)
1239d5c7916fSJason Gunthorpe 		inlen += sizeof(*pas) *
1240d5c7916fSJason Gunthorpe 			 roundup(ib_umem_num_dma_blocks(umem, page_size), 2);
12411b9a07eeSLeon Romanovsky 	in = kvzalloc(inlen, GFP_KERNEL);
1242e126ba97SEli Cohen 	if (!in) {
1243e126ba97SEli Cohen 		err = -ENOMEM;
1244e126ba97SEli Cohen 		goto err_1;
1245e126ba97SEli Cohen 	}
1246ec22eb53SSaeed Mahameed 	pas = (__be64 *)MLX5_ADDR_OF(create_mkey_in, in, klm_pas_mtt);
12478383da3eSJason Gunthorpe 	if (populate) {
12488383da3eSJason Gunthorpe 		if (WARN_ON(access_flags & IB_ACCESS_ON_DEMAND)) {
12498383da3eSJason Gunthorpe 			err = -EINVAL;
12508383da3eSJason Gunthorpe 			goto err_2;
12518383da3eSJason Gunthorpe 		}
1252d5c7916fSJason Gunthorpe 		mlx5_ib_populate_pas(umem, 1UL << mr->page_shift, pas,
1253cc149f75SHaggai Eran 				     pg_cap ? MLX5_IB_MTT_PRESENT : 0);
12548383da3eSJason Gunthorpe 	}
1255e126ba97SEli Cohen 
1256ec22eb53SSaeed Mahameed 	/* The pg_access bit allows setting the access flags
1257d3c22457SRohit Chavan 	 * in the page list submitted with the command.
1258d3c22457SRohit Chavan 	 */
1259ec22eb53SSaeed Mahameed 	MLX5_SET(create_mkey_in, in, pg_access, !!(pg_cap));
1260ec22eb53SSaeed Mahameed 
1261ec22eb53SSaeed Mahameed 	mkc = MLX5_ADDR_OF(create_mkey_in, in, memory_key_mkey_entry);
1262f0093fb1SJason Gunthorpe 	set_mkc_access_pd_addr_fields(mkc, access_flags, iova,
12635eb29f0dSJason Gunthorpe 				      populate ? pd : dev->umrc.pd);
1264ff740aefSIlya Lesokhin 	MLX5_SET(mkc, mkc, free, !populate);
1265cdbd0d2bSAriel Levkovich 	MLX5_SET(mkc, mkc, access_mode_1_0, MLX5_MKC_ACCESS_MODE_MTT);
12668b7ff7f3SIlya Lesokhin 	MLX5_SET(mkc, mkc, umr_en, 1);
1267ec22eb53SSaeed Mahameed 
1268f0093fb1SJason Gunthorpe 	MLX5_SET64(mkc, mkc, len, umem->length);
1269ec22eb53SSaeed Mahameed 	MLX5_SET(mkc, mkc, bsf_octword_size, 0);
1270ec22eb53SSaeed Mahameed 	MLX5_SET(mkc, mkc, translations_octword_size,
1271d5c7916fSJason Gunthorpe 		 get_octo_len(iova, umem->length, mr->page_shift));
1272d5c7916fSJason Gunthorpe 	MLX5_SET(mkc, mkc, log_page_size, mr->page_shift);
127372b2f760SJason Gunthorpe 	if (mlx5_umem_needs_ats(dev, umem, access_flags))
127472b2f760SJason Gunthorpe 		MLX5_SET(mkc, mkc, ma_translation_mode, 1);
1275ff740aefSIlya Lesokhin 	if (populate) {
1276ec22eb53SSaeed Mahameed 		MLX5_SET(create_mkey_in, in, translations_octword_actual_size,
1277d5c7916fSJason Gunthorpe 			 get_octo_len(iova, umem->length, mr->page_shift));
1278ff740aefSIlya Lesokhin 	}
1279ec22eb53SSaeed Mahameed 
1280fc6a9f86SSaeed Mahameed 	err = mlx5_ib_create_mkey(dev, &mr->mmkey, in, inlen);
1281e126ba97SEli Cohen 	if (err) {
1282e126ba97SEli Cohen 		mlx5_ib_warn(dev, "create mkey failed\n");
1283e126ba97SEli Cohen 		goto err_2;
1284e126ba97SEli Cohen 	}
1285aa8e08d2SArtemy Kovalyov 	mr->mmkey.type = MLX5_MKEY_MR;
1286dd1b913fSMichael Guralnik 	mr->mmkey.ndescs = get_octo_len(iova, umem->length, mr->page_shift);
128738f8ff5bSJason Gunthorpe 	mr->umem = umem;
1288cf6a8b1bSAharon Landau 	set_mr_fields(dev, mr, umem->length, access_flags, iova);
1289479163f4SAl Viro 	kvfree(in);
1290e126ba97SEli Cohen 
1291a606b0f6SMatan Barak 	mlx5_ib_dbg(dev, "mkey = 0x%x\n", mr->mmkey.key);
1292e126ba97SEli Cohen 
1293e126ba97SEli Cohen 	return mr;
1294e126ba97SEli Cohen 
1295e126ba97SEli Cohen err_2:
1296479163f4SAl Viro 	kvfree(in);
1297e126ba97SEli Cohen err_1:
1298e126ba97SEli Cohen 	kfree(mr);
1299e126ba97SEli Cohen 	return ERR_PTR(err);
1300e126ba97SEli Cohen }
1301e126ba97SEli Cohen 
mlx5_ib_get_dm_mr(struct ib_pd * pd,u64 start_addr,u64 length,int acc,int mode)13023b113a1eSAriel Levkovich static struct ib_mr *mlx5_ib_get_dm_mr(struct ib_pd *pd, u64 start_addr,
13033b113a1eSAriel Levkovich 				       u64 length, int acc, int mode)
13046c29f57eSAriel Levkovich {
13056c29f57eSAriel Levkovich 	struct mlx5_ib_dev *dev = to_mdev(pd->device);
13066c29f57eSAriel Levkovich 	int inlen = MLX5_ST_SZ_BYTES(create_mkey_in);
13076c29f57eSAriel Levkovich 	struct mlx5_ib_mr *mr;
13086c29f57eSAriel Levkovich 	void *mkc;
13096c29f57eSAriel Levkovich 	u32 *in;
13106c29f57eSAriel Levkovich 	int err;
13116c29f57eSAriel Levkovich 
13126c29f57eSAriel Levkovich 	mr = kzalloc(sizeof(*mr), GFP_KERNEL);
13136c29f57eSAriel Levkovich 	if (!mr)
13146c29f57eSAriel Levkovich 		return ERR_PTR(-ENOMEM);
13156c29f57eSAriel Levkovich 
13166c29f57eSAriel Levkovich 	in = kzalloc(inlen, GFP_KERNEL);
13176c29f57eSAriel Levkovich 	if (!in) {
13186c29f57eSAriel Levkovich 		err = -ENOMEM;
13196c29f57eSAriel Levkovich 		goto err_free;
13206c29f57eSAriel Levkovich 	}
13216c29f57eSAriel Levkovich 
13226c29f57eSAriel Levkovich 	mkc = MLX5_ADDR_OF(create_mkey_in, in, memory_key_mkey_entry);
13236c29f57eSAriel Levkovich 
13243b113a1eSAriel Levkovich 	MLX5_SET(mkc, mkc, access_mode_1_0, mode & 0x3);
13253b113a1eSAriel Levkovich 	MLX5_SET(mkc, mkc, access_mode_4_2, (mode >> 2) & 0x7);
13266c29f57eSAriel Levkovich 	MLX5_SET64(mkc, mkc, len, length);
132703232cc4SParav Pandit 	set_mkc_access_pd_addr_fields(mkc, acc, start_addr, pd);
13286c29f57eSAriel Levkovich 
1329fc6a9f86SSaeed Mahameed 	err = mlx5_ib_create_mkey(dev, &mr->mmkey, in, inlen);
13306c29f57eSAriel Levkovich 	if (err)
13316c29f57eSAriel Levkovich 		goto err_in;
13326c29f57eSAriel Levkovich 
13336c29f57eSAriel Levkovich 	kfree(in);
13346c29f57eSAriel Levkovich 
1335cf6a8b1bSAharon Landau 	set_mr_fields(dev, mr, length, acc, start_addr);
13366c29f57eSAriel Levkovich 
13376c29f57eSAriel Levkovich 	return &mr->ibmr;
13386c29f57eSAriel Levkovich 
13396c29f57eSAriel Levkovich err_in:
13406c29f57eSAriel Levkovich 	kfree(in);
13416c29f57eSAriel Levkovich 
13426c29f57eSAriel Levkovich err_free:
13436c29f57eSAriel Levkovich 	kfree(mr);
13446c29f57eSAriel Levkovich 
13456c29f57eSAriel Levkovich 	return ERR_PTR(err);
13466c29f57eSAriel Levkovich }
13476c29f57eSAriel Levkovich 
mlx5_ib_advise_mr(struct ib_pd * pd,enum ib_uverbs_advise_mr_advice advice,u32 flags,struct ib_sge * sg_list,u32 num_sge,struct uverbs_attr_bundle * attrs)1348813e90b1SMoni Shoua int mlx5_ib_advise_mr(struct ib_pd *pd,
1349813e90b1SMoni Shoua 		      enum ib_uverbs_advise_mr_advice advice,
1350813e90b1SMoni Shoua 		      u32 flags,
1351813e90b1SMoni Shoua 		      struct ib_sge *sg_list,
1352813e90b1SMoni Shoua 		      u32 num_sge,
1353813e90b1SMoni Shoua 		      struct uverbs_attr_bundle *attrs)
1354813e90b1SMoni Shoua {
1355813e90b1SMoni Shoua 	if (advice != IB_UVERBS_ADVISE_MR_ADVICE_PREFETCH &&
1356677cf51fSYishai Hadas 	    advice != IB_UVERBS_ADVISE_MR_ADVICE_PREFETCH_WRITE &&
1357677cf51fSYishai Hadas 	    advice != IB_UVERBS_ADVISE_MR_ADVICE_PREFETCH_NO_FAULT)
1358813e90b1SMoni Shoua 		return -EOPNOTSUPP;
1359813e90b1SMoni Shoua 
1360813e90b1SMoni Shoua 	return mlx5_ib_advise_mr_prefetch(pd, advice, flags,
1361813e90b1SMoni Shoua 					 sg_list, num_sge);
1362813e90b1SMoni Shoua }
1363813e90b1SMoni Shoua 
mlx5_ib_reg_dm_mr(struct ib_pd * pd,struct ib_dm * dm,struct ib_dm_mr_attr * attr,struct uverbs_attr_bundle * attrs)13646c29f57eSAriel Levkovich struct ib_mr *mlx5_ib_reg_dm_mr(struct ib_pd *pd, struct ib_dm *dm,
13656c29f57eSAriel Levkovich 				struct ib_dm_mr_attr *attr,
13666c29f57eSAriel Levkovich 				struct uverbs_attr_bundle *attrs)
13676c29f57eSAriel Levkovich {
13686c29f57eSAriel Levkovich 	struct mlx5_ib_dm *mdm = to_mdm(dm);
13693b113a1eSAriel Levkovich 	struct mlx5_core_dev *dev = to_mdev(dm->device)->mdev;
13703b113a1eSAriel Levkovich 	u64 start_addr = mdm->dev_addr + attr->offset;
13713b113a1eSAriel Levkovich 	int mode;
13726c29f57eSAriel Levkovich 
13733b113a1eSAriel Levkovich 	switch (mdm->type) {
13743b113a1eSAriel Levkovich 	case MLX5_IB_UAPI_DM_TYPE_MEMIC:
13753b113a1eSAriel Levkovich 		if (attr->access_flags & ~MLX5_IB_DM_MEMIC_ALLOWED_ACCESS)
13766c29f57eSAriel Levkovich 			return ERR_PTR(-EINVAL);
13776c29f57eSAriel Levkovich 
13783b113a1eSAriel Levkovich 		mode = MLX5_MKC_ACCESS_MODE_MEMIC;
13793b113a1eSAriel Levkovich 		start_addr -= pci_resource_start(dev->pdev, 0);
13803b113a1eSAriel Levkovich 		break;
138125c13324SAriel Levkovich 	case MLX5_IB_UAPI_DM_TYPE_STEERING_SW_ICM:
138225c13324SAriel Levkovich 	case MLX5_IB_UAPI_DM_TYPE_HEADER_MODIFY_SW_ICM:
1383a6492af3SYevgeny Kliteynik 	case MLX5_IB_UAPI_DM_TYPE_HEADER_MODIFY_PATTERN_SW_ICM:
138425c13324SAriel Levkovich 		if (attr->access_flags & ~MLX5_IB_DM_SW_ICM_ALLOWED_ACCESS)
138525c13324SAriel Levkovich 			return ERR_PTR(-EINVAL);
138625c13324SAriel Levkovich 
138725c13324SAriel Levkovich 		mode = MLX5_MKC_ACCESS_MODE_SW_ICM;
138825c13324SAriel Levkovich 		break;
13893b113a1eSAriel Levkovich 	default:
13903b113a1eSAriel Levkovich 		return ERR_PTR(-EINVAL);
13913b113a1eSAriel Levkovich 	}
13926c29f57eSAriel Levkovich 
13933b113a1eSAriel Levkovich 	return mlx5_ib_get_dm_mr(pd, start_addr, attr->length,
13943b113a1eSAriel Levkovich 				 attr->access_flags, mode);
13956c29f57eSAriel Levkovich }
13966c29f57eSAriel Levkovich 
create_real_mr(struct ib_pd * pd,struct ib_umem * umem,u64 iova,int access_flags)139738f8ff5bSJason Gunthorpe static struct ib_mr *create_real_mr(struct ib_pd *pd, struct ib_umem *umem,
139838f8ff5bSJason Gunthorpe 				    u64 iova, int access_flags)
1399e126ba97SEli Cohen {
1400e126ba97SEli Cohen 	struct mlx5_ib_dev *dev = to_mdev(pd->device);
1401e126ba97SEli Cohen 	struct mlx5_ib_mr *mr = NULL;
14028383da3eSJason Gunthorpe 	bool xlt_with_umr;
1403e126ba97SEli Cohen 	int err;
1404e126ba97SEli Cohen 
1405f49c856aSAharon Landau 	xlt_with_umr = mlx5r_umr_can_load_pas(dev, umem->length);
14068383da3eSJason Gunthorpe 	if (xlt_with_umr) {
140738f8ff5bSJason Gunthorpe 		mr = alloc_cacheable_mr(pd, umem, iova, access_flags);
140838f8ff5bSJason Gunthorpe 	} else {
1409ef3642c4SJason Gunthorpe 		unsigned int page_size = mlx5_umem_find_best_pgsz(
1410ef3642c4SJason Gunthorpe 			umem, mkc, log_page_size, 0, iova);
1411ef3642c4SJason Gunthorpe 
14126bc1a656SMoshe Lazer 		mutex_lock(&dev->slow_path_mutex);
1413ef3642c4SJason Gunthorpe 		mr = reg_create(pd, umem, iova, access_flags, page_size, true);
14146bc1a656SMoshe Lazer 		mutex_unlock(&dev->slow_path_mutex);
14156bc1a656SMoshe Lazer 	}
1416e126ba97SEli Cohen 	if (IS_ERR(mr)) {
141738f8ff5bSJason Gunthorpe 		ib_umem_release(umem);
141838f8ff5bSJason Gunthorpe 		return ERR_CAST(mr);
1419e126ba97SEli Cohen 	}
1420e126ba97SEli Cohen 
1421a606b0f6SMatan Barak 	mlx5_ib_dbg(dev, "mkey 0x%x\n", mr->mmkey.key);
1422e126ba97SEli Cohen 
142338f8ff5bSJason Gunthorpe 	atomic_add(ib_umem_num_pages(umem), &dev->mdev->priv.reg_pages);
1424e126ba97SEli Cohen 
142538f8ff5bSJason Gunthorpe 	if (xlt_with_umr) {
14268383da3eSJason Gunthorpe 		/*
14278383da3eSJason Gunthorpe 		 * If the MR was created with reg_create then it will be
14288383da3eSJason Gunthorpe 		 * configured properly but left disabled. It is safe to go ahead
14298383da3eSJason Gunthorpe 		 * and configure it again via UMR while enabling it.
14308383da3eSJason Gunthorpe 		 */
1431b3d47ebdSAharon Landau 		err = mlx5r_umr_update_mr_pas(mr, MLX5_IB_UPD_XLT_ENABLE);
1432ff740aefSIlya Lesokhin 		if (err) {
1433e6fb246cSJason Gunthorpe 			mlx5_ib_dereg_mr(&mr->ibmr, NULL);
1434ff740aefSIlya Lesokhin 			return ERR_PTR(err);
1435ff740aefSIlya Lesokhin 		}
1436ff740aefSIlya Lesokhin 	}
143738f8ff5bSJason Gunthorpe 	return &mr->ibmr;
143838f8ff5bSJason Gunthorpe }
1439ff740aefSIlya Lesokhin 
create_user_odp_mr(struct ib_pd * pd,u64 start,u64 length,u64 iova,int access_flags,struct ib_udata * udata)144038f8ff5bSJason Gunthorpe static struct ib_mr *create_user_odp_mr(struct ib_pd *pd, u64 start, u64 length,
144138f8ff5bSJason Gunthorpe 					u64 iova, int access_flags,
144238f8ff5bSJason Gunthorpe 					struct ib_udata *udata)
144338f8ff5bSJason Gunthorpe {
144438f8ff5bSJason Gunthorpe 	struct mlx5_ib_dev *dev = to_mdev(pd->device);
144538f8ff5bSJason Gunthorpe 	struct ib_umem_odp *odp;
144638f8ff5bSJason Gunthorpe 	struct mlx5_ib_mr *mr;
144738f8ff5bSJason Gunthorpe 	int err;
144838f8ff5bSJason Gunthorpe 
144938f8ff5bSJason Gunthorpe 	if (!IS_ENABLED(CONFIG_INFINIBAND_ON_DEMAND_PAGING))
145038f8ff5bSJason Gunthorpe 		return ERR_PTR(-EOPNOTSUPP);
145138f8ff5bSJason Gunthorpe 
1452ad50294dSShay Drory 	err = mlx5r_odp_create_eq(dev, &dev->odp_pf_eq);
1453ad50294dSShay Drory 	if (err)
1454ad50294dSShay Drory 		return ERR_PTR(err);
145538f8ff5bSJason Gunthorpe 	if (!start && length == U64_MAX) {
145638f8ff5bSJason Gunthorpe 		if (iova != 0)
145738f8ff5bSJason Gunthorpe 			return ERR_PTR(-EINVAL);
145838f8ff5bSJason Gunthorpe 		if (!(dev->odp_caps.general_caps & IB_ODP_SUPPORT_IMPLICIT))
145938f8ff5bSJason Gunthorpe 			return ERR_PTR(-EINVAL);
146038f8ff5bSJason Gunthorpe 
14610bedd3d0SLang Cheng 		mr = mlx5_ib_alloc_implicit_mr(to_mpd(pd), access_flags);
146238f8ff5bSJason Gunthorpe 		if (IS_ERR(mr))
146338f8ff5bSJason Gunthorpe 			return ERR_CAST(mr);
146438f8ff5bSJason Gunthorpe 		return &mr->ibmr;
146538f8ff5bSJason Gunthorpe 	}
146638f8ff5bSJason Gunthorpe 
146738f8ff5bSJason Gunthorpe 	/* ODP requires xlt update via umr to work. */
1468f49c856aSAharon Landau 	if (!mlx5r_umr_can_load_pas(dev, length))
146938f8ff5bSJason Gunthorpe 		return ERR_PTR(-EINVAL);
147038f8ff5bSJason Gunthorpe 
147138f8ff5bSJason Gunthorpe 	odp = ib_umem_odp_get(&dev->ib_dev, start, length, access_flags,
147238f8ff5bSJason Gunthorpe 			      &mlx5_mn_ops);
147338f8ff5bSJason Gunthorpe 	if (IS_ERR(odp))
147438f8ff5bSJason Gunthorpe 		return ERR_CAST(odp);
147538f8ff5bSJason Gunthorpe 
147638f8ff5bSJason Gunthorpe 	mr = alloc_cacheable_mr(pd, &odp->umem, iova, access_flags);
147738f8ff5bSJason Gunthorpe 	if (IS_ERR(mr)) {
147838f8ff5bSJason Gunthorpe 		ib_umem_release(&odp->umem);
147938f8ff5bSJason Gunthorpe 		return ERR_CAST(mr);
148038f8ff5bSJason Gunthorpe 	}
148155085466SAharon Landau 	xa_init(&mr->implicit_children);
148238f8ff5bSJason Gunthorpe 
148338f8ff5bSJason Gunthorpe 	odp->private = mr;
1484db72438cSYishai Hadas 	err = mlx5r_store_odp_mkey(dev, &mr->mmkey);
148538f8ff5bSJason Gunthorpe 	if (err)
148638f8ff5bSJason Gunthorpe 		goto err_dereg_mr;
1487a03bfc37SYishai Hadas 
148838f8ff5bSJason Gunthorpe 	err = mlx5_ib_init_odp_mr(mr);
148938f8ff5bSJason Gunthorpe 	if (err)
149038f8ff5bSJason Gunthorpe 		goto err_dereg_mr;
1491ff740aefSIlya Lesokhin 	return &mr->ibmr;
149238f8ff5bSJason Gunthorpe 
149338f8ff5bSJason Gunthorpe err_dereg_mr:
1494e6fb246cSJason Gunthorpe 	mlx5_ib_dereg_mr(&mr->ibmr, NULL);
1495e126ba97SEli Cohen 	return ERR_PTR(err);
1496e126ba97SEli Cohen }
1497e126ba97SEli Cohen 
mlx5_ib_reg_user_mr(struct ib_pd * pd,u64 start,u64 length,u64 iova,int access_flags,struct ib_udata * udata)149838f8ff5bSJason Gunthorpe struct ib_mr *mlx5_ib_reg_user_mr(struct ib_pd *pd, u64 start, u64 length,
149938f8ff5bSJason Gunthorpe 				  u64 iova, int access_flags,
150038f8ff5bSJason Gunthorpe 				  struct ib_udata *udata)
150138f8ff5bSJason Gunthorpe {
150238f8ff5bSJason Gunthorpe 	struct mlx5_ib_dev *dev = to_mdev(pd->device);
150338f8ff5bSJason Gunthorpe 	struct ib_umem *umem;
150438f8ff5bSJason Gunthorpe 
150538f8ff5bSJason Gunthorpe 	if (!IS_ENABLED(CONFIG_INFINIBAND_USER_MEM))
150638f8ff5bSJason Gunthorpe 		return ERR_PTR(-EOPNOTSUPP);
150738f8ff5bSJason Gunthorpe 
150838f8ff5bSJason Gunthorpe 	mlx5_ib_dbg(dev, "start 0x%llx, iova 0x%llx, length 0x%llx, access_flags 0x%x\n",
150938f8ff5bSJason Gunthorpe 		    start, iova, length, access_flags);
151038f8ff5bSJason Gunthorpe 
151138f8ff5bSJason Gunthorpe 	if (access_flags & IB_ACCESS_ON_DEMAND)
151238f8ff5bSJason Gunthorpe 		return create_user_odp_mr(pd, start, length, iova, access_flags,
151338f8ff5bSJason Gunthorpe 					  udata);
151438f8ff5bSJason Gunthorpe 	umem = ib_umem_get(&dev->ib_dev, start, length, access_flags);
151538f8ff5bSJason Gunthorpe 	if (IS_ERR(umem))
151638f8ff5bSJason Gunthorpe 		return ERR_CAST(umem);
151738f8ff5bSJason Gunthorpe 	return create_real_mr(pd, umem, iova, access_flags);
151838f8ff5bSJason Gunthorpe }
151938f8ff5bSJason Gunthorpe 
mlx5_ib_dmabuf_invalidate_cb(struct dma_buf_attachment * attach)152090da7dc8SJianxin Xiong static void mlx5_ib_dmabuf_invalidate_cb(struct dma_buf_attachment *attach)
152190da7dc8SJianxin Xiong {
152290da7dc8SJianxin Xiong 	struct ib_umem_dmabuf *umem_dmabuf = attach->importer_priv;
152390da7dc8SJianxin Xiong 	struct mlx5_ib_mr *mr = umem_dmabuf->private;
152490da7dc8SJianxin Xiong 
152590da7dc8SJianxin Xiong 	dma_resv_assert_held(umem_dmabuf->attach->dmabuf->resv);
152690da7dc8SJianxin Xiong 
152790da7dc8SJianxin Xiong 	if (!umem_dmabuf->sgt)
152890da7dc8SJianxin Xiong 		return;
152990da7dc8SJianxin Xiong 
1530b3d47ebdSAharon Landau 	mlx5r_umr_update_mr_pas(mr, MLX5_IB_UPD_XLT_ZAP);
153190da7dc8SJianxin Xiong 	ib_umem_dmabuf_unmap_pages(umem_dmabuf);
153290da7dc8SJianxin Xiong }
153390da7dc8SJianxin Xiong 
153490da7dc8SJianxin Xiong static struct dma_buf_attach_ops mlx5_ib_dmabuf_attach_ops = {
153590da7dc8SJianxin Xiong 	.allow_peer2peer = 1,
153690da7dc8SJianxin Xiong 	.move_notify = mlx5_ib_dmabuf_invalidate_cb,
153790da7dc8SJianxin Xiong };
153890da7dc8SJianxin Xiong 
mlx5_ib_reg_user_mr_dmabuf(struct ib_pd * pd,u64 offset,u64 length,u64 virt_addr,int fd,int access_flags,struct ib_udata * udata)153990da7dc8SJianxin Xiong struct ib_mr *mlx5_ib_reg_user_mr_dmabuf(struct ib_pd *pd, u64 offset,
154090da7dc8SJianxin Xiong 					 u64 length, u64 virt_addr,
154190da7dc8SJianxin Xiong 					 int fd, int access_flags,
154290da7dc8SJianxin Xiong 					 struct ib_udata *udata)
154390da7dc8SJianxin Xiong {
154490da7dc8SJianxin Xiong 	struct mlx5_ib_dev *dev = to_mdev(pd->device);
154590da7dc8SJianxin Xiong 	struct mlx5_ib_mr *mr = NULL;
154690da7dc8SJianxin Xiong 	struct ib_umem_dmabuf *umem_dmabuf;
154790da7dc8SJianxin Xiong 	int err;
154890da7dc8SJianxin Xiong 
154990da7dc8SJianxin Xiong 	if (!IS_ENABLED(CONFIG_INFINIBAND_USER_MEM) ||
155090da7dc8SJianxin Xiong 	    !IS_ENABLED(CONFIG_INFINIBAND_ON_DEMAND_PAGING))
155190da7dc8SJianxin Xiong 		return ERR_PTR(-EOPNOTSUPP);
155290da7dc8SJianxin Xiong 
155390da7dc8SJianxin Xiong 	mlx5_ib_dbg(dev,
155490da7dc8SJianxin Xiong 		    "offset 0x%llx, virt_addr 0x%llx, length 0x%llx, fd %d, access_flags 0x%x\n",
155590da7dc8SJianxin Xiong 		    offset, virt_addr, length, fd, access_flags);
155690da7dc8SJianxin Xiong 
155790da7dc8SJianxin Xiong 	/* dmabuf requires xlt update via umr to work. */
1558f49c856aSAharon Landau 	if (!mlx5r_umr_can_load_pas(dev, length))
155990da7dc8SJianxin Xiong 		return ERR_PTR(-EINVAL);
156090da7dc8SJianxin Xiong 
156190da7dc8SJianxin Xiong 	umem_dmabuf = ib_umem_dmabuf_get(&dev->ib_dev, offset, length, fd,
156290da7dc8SJianxin Xiong 					 access_flags,
156390da7dc8SJianxin Xiong 					 &mlx5_ib_dmabuf_attach_ops);
156490da7dc8SJianxin Xiong 	if (IS_ERR(umem_dmabuf)) {
156590da7dc8SJianxin Xiong 		mlx5_ib_dbg(dev, "umem_dmabuf get failed (%ld)\n",
156690da7dc8SJianxin Xiong 			    PTR_ERR(umem_dmabuf));
156790da7dc8SJianxin Xiong 		return ERR_CAST(umem_dmabuf);
156890da7dc8SJianxin Xiong 	}
156990da7dc8SJianxin Xiong 
157090da7dc8SJianxin Xiong 	mr = alloc_cacheable_mr(pd, &umem_dmabuf->umem, virt_addr,
157190da7dc8SJianxin Xiong 				access_flags);
157290da7dc8SJianxin Xiong 	if (IS_ERR(mr)) {
157390da7dc8SJianxin Xiong 		ib_umem_release(&umem_dmabuf->umem);
157490da7dc8SJianxin Xiong 		return ERR_CAST(mr);
157590da7dc8SJianxin Xiong 	}
157690da7dc8SJianxin Xiong 
157790da7dc8SJianxin Xiong 	mlx5_ib_dbg(dev, "mkey 0x%x\n", mr->mmkey.key);
157890da7dc8SJianxin Xiong 
157990da7dc8SJianxin Xiong 	atomic_add(ib_umem_num_pages(mr->umem), &dev->mdev->priv.reg_pages);
158090da7dc8SJianxin Xiong 	umem_dmabuf->private = mr;
1581db72438cSYishai Hadas 	err = mlx5r_store_odp_mkey(dev, &mr->mmkey);
158290da7dc8SJianxin Xiong 	if (err)
158390da7dc8SJianxin Xiong 		goto err_dereg_mr;
158490da7dc8SJianxin Xiong 
158590da7dc8SJianxin Xiong 	err = mlx5_ib_init_dmabuf_mr(mr);
158690da7dc8SJianxin Xiong 	if (err)
158790da7dc8SJianxin Xiong 		goto err_dereg_mr;
158890da7dc8SJianxin Xiong 	return &mr->ibmr;
158990da7dc8SJianxin Xiong 
159090da7dc8SJianxin Xiong err_dereg_mr:
1591e6fb246cSJason Gunthorpe 	mlx5_ib_dereg_mr(&mr->ibmr, NULL);
159290da7dc8SJianxin Xiong 	return ERR_PTR(err);
159390da7dc8SJianxin Xiong }
159490da7dc8SJianxin Xiong 
1595ef3642c4SJason Gunthorpe /*
1596ef3642c4SJason Gunthorpe  * True if the change in access flags can be done via UMR, only some access
1597ef3642c4SJason Gunthorpe  * flags can be updated.
1598ef3642c4SJason Gunthorpe  */
can_use_umr_rereg_access(struct mlx5_ib_dev * dev,unsigned int current_access_flags,unsigned int target_access_flags)1599ef3642c4SJason Gunthorpe static bool can_use_umr_rereg_access(struct mlx5_ib_dev *dev,
1600ef3642c4SJason Gunthorpe 				     unsigned int current_access_flags,
1601ef3642c4SJason Gunthorpe 				     unsigned int target_access_flags)
160256e11d62SNoa Osherovich {
1603ef3642c4SJason Gunthorpe 	unsigned int diffs = current_access_flags ^ target_access_flags;
160456e11d62SNoa Osherovich 
1605ef3642c4SJason Gunthorpe 	if (diffs & ~(IB_ACCESS_LOCAL_WRITE | IB_ACCESS_REMOTE_WRITE |
1606499569c8SOr Har-Toov 		      IB_ACCESS_REMOTE_READ | IB_ACCESS_RELAXED_ORDERING |
1607499569c8SOr Har-Toov 		      IB_ACCESS_REMOTE_ATOMIC))
1608ef3642c4SJason Gunthorpe 		return false;
1609f49c856aSAharon Landau 	return mlx5r_umr_can_reconfig(dev, current_access_flags,
1610ef3642c4SJason Gunthorpe 				      target_access_flags);
161156e11d62SNoa Osherovich }
161256e11d62SNoa Osherovich 
can_use_umr_rereg_pas(struct mlx5_ib_mr * mr,struct ib_umem * new_umem,int new_access_flags,u64 iova,unsigned long * page_size)1613ef3642c4SJason Gunthorpe static bool can_use_umr_rereg_pas(struct mlx5_ib_mr *mr,
1614ef3642c4SJason Gunthorpe 				  struct ib_umem *new_umem,
1615ef3642c4SJason Gunthorpe 				  int new_access_flags, u64 iova,
1616ef3642c4SJason Gunthorpe 				  unsigned long *page_size)
1617ef3642c4SJason Gunthorpe {
1618ef3642c4SJason Gunthorpe 	struct mlx5_ib_dev *dev = to_mdev(mr->ibmr.device);
1619ef3642c4SJason Gunthorpe 
1620ef3642c4SJason Gunthorpe 	/* We only track the allocated sizes of MRs from the cache */
16216b753386SAharon Landau 	if (!mr->mmkey.cache_ent)
1622ef3642c4SJason Gunthorpe 		return false;
1623f49c856aSAharon Landau 	if (!mlx5r_umr_can_load_pas(dev, new_umem->length))
1624ef3642c4SJason Gunthorpe 		return false;
1625ef3642c4SJason Gunthorpe 
1626ef3642c4SJason Gunthorpe 	*page_size =
1627ef3642c4SJason Gunthorpe 		mlx5_umem_find_best_pgsz(new_umem, mkc, log_page_size, 0, iova);
1628ef3642c4SJason Gunthorpe 	if (WARN_ON(!*page_size))
1629ef3642c4SJason Gunthorpe 		return false;
163073d09b2fSMichael Guralnik 	return (mr->mmkey.cache_ent->rb_key.ndescs) >=
1631ef3642c4SJason Gunthorpe 	       ib_umem_num_dma_blocks(new_umem, *page_size);
1632ef3642c4SJason Gunthorpe }
1633ef3642c4SJason Gunthorpe 
umr_rereg_pas(struct mlx5_ib_mr * mr,struct ib_pd * pd,int access_flags,int flags,struct ib_umem * new_umem,u64 iova,unsigned long page_size)1634ef3642c4SJason Gunthorpe static int umr_rereg_pas(struct mlx5_ib_mr *mr, struct ib_pd *pd,
1635ef3642c4SJason Gunthorpe 			 int access_flags, int flags, struct ib_umem *new_umem,
1636ef3642c4SJason Gunthorpe 			 u64 iova, unsigned long page_size)
1637ef3642c4SJason Gunthorpe {
1638ef3642c4SJason Gunthorpe 	struct mlx5_ib_dev *dev = to_mdev(mr->ibmr.device);
1639ef3642c4SJason Gunthorpe 	int upd_flags = MLX5_IB_UPD_XLT_ADDR | MLX5_IB_UPD_XLT_ENABLE;
1640ef3642c4SJason Gunthorpe 	struct ib_umem *old_umem = mr->umem;
1641ef3642c4SJason Gunthorpe 	int err;
1642ef3642c4SJason Gunthorpe 
1643ef3642c4SJason Gunthorpe 	/*
1644ef3642c4SJason Gunthorpe 	 * To keep everything simple the MR is revoked before we start to mess
1645ef3642c4SJason Gunthorpe 	 * with it. This ensure the change is atomic relative to any use of the
1646ef3642c4SJason Gunthorpe 	 * MR.
1647ef3642c4SJason Gunthorpe 	 */
164833e8aa8eSAharon Landau 	err = mlx5r_umr_revoke_mr(mr);
1649ef3642c4SJason Gunthorpe 	if (err)
1650ef3642c4SJason Gunthorpe 		return err;
1651ef3642c4SJason Gunthorpe 
1652ef3642c4SJason Gunthorpe 	if (flags & IB_MR_REREG_PD) {
1653ef3642c4SJason Gunthorpe 		mr->ibmr.pd = pd;
1654ef3642c4SJason Gunthorpe 		upd_flags |= MLX5_IB_UPD_XLT_PD;
1655ef3642c4SJason Gunthorpe 	}
1656ef3642c4SJason Gunthorpe 	if (flags & IB_MR_REREG_ACCESS) {
1657ef3642c4SJason Gunthorpe 		mr->access_flags = access_flags;
1658ef3642c4SJason Gunthorpe 		upd_flags |= MLX5_IB_UPD_XLT_ACCESS;
1659ef3642c4SJason Gunthorpe 	}
1660ef3642c4SJason Gunthorpe 
1661cf6a8b1bSAharon Landau 	mr->ibmr.iova = iova;
1662062fd731SAharon Landau 	mr->ibmr.length = new_umem->length;
1663ef3642c4SJason Gunthorpe 	mr->page_shift = order_base_2(page_size);
1664ef3642c4SJason Gunthorpe 	mr->umem = new_umem;
1665b3d47ebdSAharon Landau 	err = mlx5r_umr_update_mr_pas(mr, upd_flags);
1666ef3642c4SJason Gunthorpe 	if (err) {
1667ef3642c4SJason Gunthorpe 		/*
1668ef3642c4SJason Gunthorpe 		 * The MR is revoked at this point so there is no issue to free
1669ef3642c4SJason Gunthorpe 		 * new_umem.
1670ef3642c4SJason Gunthorpe 		 */
1671ef3642c4SJason Gunthorpe 		mr->umem = old_umem;
167256e11d62SNoa Osherovich 		return err;
167356e11d62SNoa Osherovich 	}
167456e11d62SNoa Osherovich 
1675ef3642c4SJason Gunthorpe 	atomic_sub(ib_umem_num_pages(old_umem), &dev->mdev->priv.reg_pages);
1676ef3642c4SJason Gunthorpe 	ib_umem_release(old_umem);
1677ef3642c4SJason Gunthorpe 	atomic_add(ib_umem_num_pages(new_umem), &dev->mdev->priv.reg_pages);
1678ef3642c4SJason Gunthorpe 	return 0;
1679ef3642c4SJason Gunthorpe }
1680ef3642c4SJason Gunthorpe 
mlx5_ib_rereg_user_mr(struct ib_mr * ib_mr,int flags,u64 start,u64 length,u64 iova,int new_access_flags,struct ib_pd * new_pd,struct ib_udata * udata)16816e0954b1SJason Gunthorpe struct ib_mr *mlx5_ib_rereg_user_mr(struct ib_mr *ib_mr, int flags, u64 start,
1682ef3642c4SJason Gunthorpe 				    u64 length, u64 iova, int new_access_flags,
1683ef3642c4SJason Gunthorpe 				    struct ib_pd *new_pd,
16846e0954b1SJason Gunthorpe 				    struct ib_udata *udata)
168556e11d62SNoa Osherovich {
168656e11d62SNoa Osherovich 	struct mlx5_ib_dev *dev = to_mdev(ib_mr->device);
168756e11d62SNoa Osherovich 	struct mlx5_ib_mr *mr = to_mmr(ib_mr);
168856e11d62SNoa Osherovich 	int err;
168956e11d62SNoa Osherovich 
1690ef3642c4SJason Gunthorpe 	if (!IS_ENABLED(CONFIG_INFINIBAND_USER_MEM))
16916e0954b1SJason Gunthorpe 		return ERR_PTR(-EOPNOTSUPP);
1692880505cfSJason Gunthorpe 
1693ef3642c4SJason Gunthorpe 	mlx5_ib_dbg(
1694ef3642c4SJason Gunthorpe 		dev,
1695ef3642c4SJason Gunthorpe 		"start 0x%llx, iova 0x%llx, length 0x%llx, access_flags 0x%x\n",
1696ef3642c4SJason Gunthorpe 		start, iova, length, new_access_flags);
1697b4bd701aSLeon Romanovsky 
1698ef3642c4SJason Gunthorpe 	if (flags & ~(IB_MR_REREG_TRANS | IB_MR_REREG_PD | IB_MR_REREG_ACCESS))
1699ef3642c4SJason Gunthorpe 		return ERR_PTR(-EOPNOTSUPP);
170056e11d62SNoa Osherovich 
1701ef3642c4SJason Gunthorpe 	if (!(flags & IB_MR_REREG_ACCESS))
1702ef3642c4SJason Gunthorpe 		new_access_flags = mr->access_flags;
1703ef3642c4SJason Gunthorpe 	if (!(flags & IB_MR_REREG_PD))
1704ef3642c4SJason Gunthorpe 		new_pd = ib_mr->pd;
1705ef3642c4SJason Gunthorpe 
1706ef3642c4SJason Gunthorpe 	if (!(flags & IB_MR_REREG_TRANS)) {
1707ef3642c4SJason Gunthorpe 		struct ib_umem *umem;
1708ef3642c4SJason Gunthorpe 
1709ef3642c4SJason Gunthorpe 		/* Fast path for PD/access change */
1710ef3642c4SJason Gunthorpe 		if (can_use_umr_rereg_access(dev, mr->access_flags,
1711ef3642c4SJason Gunthorpe 					     new_access_flags)) {
171248319676SAharon Landau 			err = mlx5r_umr_rereg_pd_access(mr, new_pd,
171348319676SAharon Landau 							new_access_flags);
171456e11d62SNoa Osherovich 			if (err)
17156e0954b1SJason Gunthorpe 				return ERR_PTR(err);
1716ef3642c4SJason Gunthorpe 			return NULL;
1717ef3642c4SJason Gunthorpe 		}
171890da7dc8SJianxin Xiong 		/* DM or ODP MR's don't have a normal umem so we can't re-use it */
171990da7dc8SJianxin Xiong 		if (!mr->umem || is_odp_mr(mr) || is_dmabuf_mr(mr))
1720ef3642c4SJason Gunthorpe 			goto recreate;
1721ef3642c4SJason Gunthorpe 
1722ef3642c4SJason Gunthorpe 		/*
1723ef3642c4SJason Gunthorpe 		 * Only one active MR can refer to a umem at one time, revoke
1724ef3642c4SJason Gunthorpe 		 * the old MR before assigning the umem to the new one.
1725ef3642c4SJason Gunthorpe 		 */
172633e8aa8eSAharon Landau 		err = mlx5r_umr_revoke_mr(mr);
1727ef3642c4SJason Gunthorpe 		if (err)
1728ef3642c4SJason Gunthorpe 			return ERR_PTR(err);
1729ef3642c4SJason Gunthorpe 		umem = mr->umem;
1730ef3642c4SJason Gunthorpe 		mr->umem = NULL;
1731ef3642c4SJason Gunthorpe 		atomic_sub(ib_umem_num_pages(umem), &dev->mdev->priv.reg_pages);
1732ef3642c4SJason Gunthorpe 
1733cf6a8b1bSAharon Landau 		return create_real_mr(new_pd, umem, mr->ibmr.iova,
1734ef3642c4SJason Gunthorpe 				      new_access_flags);
1735ef3642c4SJason Gunthorpe 	}
1736ef3642c4SJason Gunthorpe 
1737ef3642c4SJason Gunthorpe 	/*
173890da7dc8SJianxin Xiong 	 * DM doesn't have a PAS list so we can't re-use it, odp/dmabuf does
173990da7dc8SJianxin Xiong 	 * but the logic around releasing the umem is different
1740ef3642c4SJason Gunthorpe 	 */
174190da7dc8SJianxin Xiong 	if (!mr->umem || is_odp_mr(mr) || is_dmabuf_mr(mr))
1742ef3642c4SJason Gunthorpe 		goto recreate;
1743ef3642c4SJason Gunthorpe 
1744ef3642c4SJason Gunthorpe 	if (!(new_access_flags & IB_ACCESS_ON_DEMAND) &&
1745ef3642c4SJason Gunthorpe 	    can_use_umr_rereg_access(dev, mr->access_flags, new_access_flags)) {
1746ef3642c4SJason Gunthorpe 		struct ib_umem *new_umem;
1747ef3642c4SJason Gunthorpe 		unsigned long page_size;
1748ef3642c4SJason Gunthorpe 
1749ef3642c4SJason Gunthorpe 		new_umem = ib_umem_get(&dev->ib_dev, start, length,
1750ef3642c4SJason Gunthorpe 				       new_access_flags);
1751ef3642c4SJason Gunthorpe 		if (IS_ERR(new_umem))
1752ef3642c4SJason Gunthorpe 			return ERR_CAST(new_umem);
1753ef3642c4SJason Gunthorpe 
1754ef3642c4SJason Gunthorpe 		/* Fast path for PAS change */
1755ef3642c4SJason Gunthorpe 		if (can_use_umr_rereg_pas(mr, new_umem, new_access_flags, iova,
1756ef3642c4SJason Gunthorpe 					  &page_size)) {
1757ef3642c4SJason Gunthorpe 			err = umr_rereg_pas(mr, new_pd, new_access_flags, flags,
1758ef3642c4SJason Gunthorpe 					    new_umem, iova, page_size);
1759ef3642c4SJason Gunthorpe 			if (err) {
1760ef3642c4SJason Gunthorpe 				ib_umem_release(new_umem);
1761ef3642c4SJason Gunthorpe 				return ERR_PTR(err);
1762ef3642c4SJason Gunthorpe 			}
1763ef3642c4SJason Gunthorpe 			return NULL;
1764ef3642c4SJason Gunthorpe 		}
1765ef3642c4SJason Gunthorpe 		return create_real_mr(new_pd, new_umem, iova, new_access_flags);
1766ef3642c4SJason Gunthorpe 	}
1767ef3642c4SJason Gunthorpe 
1768ef3642c4SJason Gunthorpe 	/*
1769ef3642c4SJason Gunthorpe 	 * Everything else has no state we can preserve, just create a new MR
1770ef3642c4SJason Gunthorpe 	 * from scratch
1771ef3642c4SJason Gunthorpe 	 */
1772ef3642c4SJason Gunthorpe recreate:
1773ef3642c4SJason Gunthorpe 	return mlx5_ib_reg_user_mr(new_pd, start, length, iova,
1774ef3642c4SJason Gunthorpe 				   new_access_flags, udata);
177556e11d62SNoa Osherovich }
177656e11d62SNoa Osherovich 
17778a187ee5SSagi Grimberg static int
mlx5_alloc_priv_descs(struct ib_device * device,struct mlx5_ib_mr * mr,int ndescs,int desc_size)17788a187ee5SSagi Grimberg mlx5_alloc_priv_descs(struct ib_device *device,
17798a187ee5SSagi Grimberg 		      struct mlx5_ib_mr *mr,
17808a187ee5SSagi Grimberg 		      int ndescs,
17818a187ee5SSagi Grimberg 		      int desc_size)
17828a187ee5SSagi Grimberg {
17837ec3df17SParav Pandit 	struct mlx5_ib_dev *dev = to_mdev(device);
17847ec3df17SParav Pandit 	struct device *ddev = &dev->mdev->pdev->dev;
17858a187ee5SSagi Grimberg 	int size = ndescs * desc_size;
17868a187ee5SSagi Grimberg 	int add_size;
17878a187ee5SSagi Grimberg 	int ret;
17888a187ee5SSagi Grimberg 
17898a187ee5SSagi Grimberg 	add_size = max_t(int, MLX5_UMR_ALIGN - ARCH_KMALLOC_MINALIGN, 0);
179052b4bdd2SYuanyuan Zhong 	if (is_power_of_2(MLX5_UMR_ALIGN) && add_size) {
179152b4bdd2SYuanyuan Zhong 		int end = max_t(int, MLX5_UMR_ALIGN, roundup_pow_of_two(size));
179252b4bdd2SYuanyuan Zhong 
179352b4bdd2SYuanyuan Zhong 		add_size = min_t(int, end - size, add_size);
179452b4bdd2SYuanyuan Zhong 	}
17958a187ee5SSagi Grimberg 
17968a187ee5SSagi Grimberg 	mr->descs_alloc = kzalloc(size + add_size, GFP_KERNEL);
17978a187ee5SSagi Grimberg 	if (!mr->descs_alloc)
17988a187ee5SSagi Grimberg 		return -ENOMEM;
17998a187ee5SSagi Grimberg 
18008a187ee5SSagi Grimberg 	mr->descs = PTR_ALIGN(mr->descs_alloc, MLX5_UMR_ALIGN);
18018a187ee5SSagi Grimberg 
18027ec3df17SParav Pandit 	mr->desc_map = dma_map_single(ddev, mr->descs, size, DMA_TO_DEVICE);
18037ec3df17SParav Pandit 	if (dma_mapping_error(ddev, mr->desc_map)) {
18048a187ee5SSagi Grimberg 		ret = -ENOMEM;
18058a187ee5SSagi Grimberg 		goto err;
18068a187ee5SSagi Grimberg 	}
18078a187ee5SSagi Grimberg 
18088a187ee5SSagi Grimberg 	return 0;
18098a187ee5SSagi Grimberg err:
18108a187ee5SSagi Grimberg 	kfree(mr->descs_alloc);
18118a187ee5SSagi Grimberg 
18128a187ee5SSagi Grimberg 	return ret;
18138a187ee5SSagi Grimberg }
18148a187ee5SSagi Grimberg 
18154163cb3dSMaor Gottlieb static void
mlx5_free_priv_descs(struct mlx5_ib_mr * mr)18164163cb3dSMaor Gottlieb mlx5_free_priv_descs(struct mlx5_ib_mr *mr)
18178a187ee5SSagi Grimberg {
18184163cb3dSMaor Gottlieb 	if (!mr->umem && mr->descs) {
18194163cb3dSMaor Gottlieb 		struct ib_device *device = mr->ibmr.device;
18208a187ee5SSagi Grimberg 		int size = mr->max_descs * mr->desc_size;
18214163cb3dSMaor Gottlieb 		struct mlx5_ib_dev *dev = to_mdev(device);
18228a187ee5SSagi Grimberg 
18237ec3df17SParav Pandit 		dma_unmap_single(&dev->mdev->pdev->dev, mr->desc_map, size,
18247ec3df17SParav Pandit 				 DMA_TO_DEVICE);
18258a187ee5SSagi Grimberg 		kfree(mr->descs_alloc);
18268a187ee5SSagi Grimberg 		mr->descs = NULL;
18278a187ee5SSagi Grimberg 	}
18284163cb3dSMaor Gottlieb }
18298a187ee5SSagi Grimberg 
cache_ent_find_and_store(struct mlx5_ib_dev * dev,struct mlx5_ib_mr * mr)1830dd1b913fSMichael Guralnik static int cache_ent_find_and_store(struct mlx5_ib_dev *dev,
1831dd1b913fSMichael Guralnik 				    struct mlx5_ib_mr *mr)
1832dd1b913fSMichael Guralnik {
1833dd1b913fSMichael Guralnik 	struct mlx5_mkey_cache *cache = &dev->cache;
1834dd1b913fSMichael Guralnik 	struct mlx5_cache_ent *ent;
183562712228SMichael Guralnik 	int ret;
1836dd1b913fSMichael Guralnik 
1837dd1b913fSMichael Guralnik 	if (mr->mmkey.cache_ent) {
1838dd1b913fSMichael Guralnik 		xa_lock_irq(&mr->mmkey.cache_ent->mkeys);
1839dd1b913fSMichael Guralnik 		mr->mmkey.cache_ent->in_use--;
1840dd1b913fSMichael Guralnik 		goto end;
1841dd1b913fSMichael Guralnik 	}
1842dd1b913fSMichael Guralnik 
1843dd1b913fSMichael Guralnik 	mutex_lock(&cache->rb_lock);
1844dd1b913fSMichael Guralnik 	ent = mkey_cache_ent_from_rb_key(dev, mr->mmkey.rb_key);
1845dd1b913fSMichael Guralnik 	if (ent) {
1846dd1b913fSMichael Guralnik 		if (ent->rb_key.ndescs == mr->mmkey.rb_key.ndescs) {
184762712228SMichael Guralnik 			if (ent->disabled) {
184862712228SMichael Guralnik 				mutex_unlock(&cache->rb_lock);
184962712228SMichael Guralnik 				return -EOPNOTSUPP;
185062712228SMichael Guralnik 			}
1851dd1b913fSMichael Guralnik 			mr->mmkey.cache_ent = ent;
185262712228SMichael Guralnik 			xa_lock_irq(&mr->mmkey.cache_ent->mkeys);
185362712228SMichael Guralnik 			mutex_unlock(&cache->rb_lock);
1854dd1b913fSMichael Guralnik 			goto end;
1855dd1b913fSMichael Guralnik 		}
1856dd1b913fSMichael Guralnik 	}
1857dd1b913fSMichael Guralnik 
185862712228SMichael Guralnik 	ent = mlx5r_cache_create_ent_locked(dev, mr->mmkey.rb_key, false);
185962712228SMichael Guralnik 	mutex_unlock(&cache->rb_lock);
1860dd1b913fSMichael Guralnik 	if (IS_ERR(ent))
1861dd1b913fSMichael Guralnik 		return PTR_ERR(ent);
1862dd1b913fSMichael Guralnik 
1863dd1b913fSMichael Guralnik 	mr->mmkey.cache_ent = ent;
186462712228SMichael Guralnik 	xa_lock_irq(&mr->mmkey.cache_ent->mkeys);
1865dd1b913fSMichael Guralnik 
1866dd1b913fSMichael Guralnik end:
186762712228SMichael Guralnik 	ret = push_mkey_locked(mr->mmkey.cache_ent, false,
1868dd1b913fSMichael Guralnik 			       xa_mk_value(mr->mmkey.key));
186962712228SMichael Guralnik 	xa_unlock_irq(&mr->mmkey.cache_ent->mkeys);
187062712228SMichael Guralnik 	return ret;
1871dd1b913fSMichael Guralnik }
1872dd1b913fSMichael Guralnik 
mlx5_ib_dereg_mr(struct ib_mr * ibmr,struct ib_udata * udata)1873e6fb246cSJason Gunthorpe int mlx5_ib_dereg_mr(struct ib_mr *ibmr, struct ib_udata *udata)
1874e126ba97SEli Cohen {
1875e6fb246cSJason Gunthorpe 	struct mlx5_ib_mr *mr = to_mmr(ibmr);
1876e6fb246cSJason Gunthorpe 	struct mlx5_ib_dev *dev = to_mdev(ibmr->device);
1877e6fb246cSJason Gunthorpe 	int rc;
1878e6fb246cSJason Gunthorpe 
1879e6fb246cSJason Gunthorpe 	/*
1880e6fb246cSJason Gunthorpe 	 * Any async use of the mr must hold the refcount, once the refcount
1881e6fb246cSJason Gunthorpe 	 * goes to zero no other thread, such as ODP page faults, prefetch, any
1882e6fb246cSJason Gunthorpe 	 * UMR activity, etc can touch the mkey. Thus it is safe to destroy it.
1883e6fb246cSJason Gunthorpe 	 */
1884e6fb246cSJason Gunthorpe 	if (IS_ENABLED(CONFIG_INFINIBAND_ON_DEMAND_PAGING) &&
1885e6fb246cSJason Gunthorpe 	    refcount_read(&mr->mmkey.usecount) != 0 &&
1886e6fb246cSJason Gunthorpe 	    xa_erase(&mr_to_mdev(mr)->odp_mkeys, mlx5_base_mkey(mr->mmkey.key)))
1887e6fb246cSJason Gunthorpe 		mlx5r_deref_wait_odp_mkey(&mr->mmkey);
1888e6fb246cSJason Gunthorpe 
1889e6fb246cSJason Gunthorpe 	if (ibmr->type == IB_MR_TYPE_INTEGRITY) {
18906466f03fSAharon Landau 		xa_cmpxchg(&dev->sig_mrs, mlx5_base_mkey(mr->mmkey.key),
18916466f03fSAharon Landau 			   mr->sig, NULL, GFP_KERNEL);
1892e6fb246cSJason Gunthorpe 
1893e6fb246cSJason Gunthorpe 		if (mr->mtt_mr) {
1894e6fb246cSJason Gunthorpe 			rc = mlx5_ib_dereg_mr(&mr->mtt_mr->ibmr, NULL);
1895e6fb246cSJason Gunthorpe 			if (rc)
1896e6fb246cSJason Gunthorpe 				return rc;
1897e6fb246cSJason Gunthorpe 			mr->mtt_mr = NULL;
1898e6fb246cSJason Gunthorpe 		}
1899e6fb246cSJason Gunthorpe 		if (mr->klm_mr) {
1900b5486430SLeon Romanovsky 			rc = mlx5_ib_dereg_mr(&mr->klm_mr->ibmr, NULL);
1901e6fb246cSJason Gunthorpe 			if (rc)
1902e6fb246cSJason Gunthorpe 				return rc;
1903e6fb246cSJason Gunthorpe 			mr->klm_mr = NULL;
1904e6fb246cSJason Gunthorpe 		}
1905e6fb246cSJason Gunthorpe 
19068b91ffc1SSagi Grimberg 		if (mlx5_core_destroy_psv(dev->mdev,
19078b91ffc1SSagi Grimberg 					  mr->sig->psv_memory.psv_idx))
19088b91ffc1SSagi Grimberg 			mlx5_ib_warn(dev, "failed to destroy mem psv %d\n",
19098b91ffc1SSagi Grimberg 				     mr->sig->psv_memory.psv_idx);
1910e6fb246cSJason Gunthorpe 		if (mlx5_core_destroy_psv(dev->mdev, mr->sig->psv_wire.psv_idx))
19118b91ffc1SSagi Grimberg 			mlx5_ib_warn(dev, "failed to destroy wire psv %d\n",
19128b91ffc1SSagi Grimberg 				     mr->sig->psv_wire.psv_idx);
19138b91ffc1SSagi Grimberg 		kfree(mr->sig);
19148b91ffc1SSagi Grimberg 		mr->sig = NULL;
19158b91ffc1SSagi Grimberg 	}
19168b91ffc1SSagi Grimberg 
1917e6fb246cSJason Gunthorpe 	/* Stop DMA */
1918dd1b913fSMichael Guralnik 	if (mr->umem && mlx5r_umr_can_load_pas(dev, mr->umem->length))
191919591f13SAharon Landau 		if (mlx5r_umr_revoke_mr(mr) ||
1920dd1b913fSMichael Guralnik 		    cache_ent_find_and_store(dev, mr))
19216b753386SAharon Landau 			mr->mmkey.cache_ent = NULL;
1922dd1b913fSMichael Guralnik 
19236b753386SAharon Landau 	if (!mr->mmkey.cache_ent) {
1924e6fb246cSJason Gunthorpe 		rc = destroy_mkey(to_mdev(mr->ibmr.device), mr);
1925e6fb246cSJason Gunthorpe 		if (rc)
1926e6fb246cSJason Gunthorpe 			return rc;
1927e126ba97SEli Cohen 	}
1928e126ba97SEli Cohen 
1929e6fb246cSJason Gunthorpe 	if (mr->umem) {
1930e6fb246cSJason Gunthorpe 		bool is_odp = is_odp_mr(mr);
19316aec21f6SHaggai Eran 
1932e6fb246cSJason Gunthorpe 		if (!is_odp)
1933e6fb246cSJason Gunthorpe 			atomic_sub(ib_umem_num_pages(mr->umem),
19341c3d247eSJason Gunthorpe 				   &dev->mdev->priv.reg_pages);
1935e6fb246cSJason Gunthorpe 		ib_umem_release(mr->umem);
1936e6fb246cSJason Gunthorpe 		if (is_odp)
1937e6fb246cSJason Gunthorpe 			mlx5_ib_free_odp_mr(mr);
19381c3d247eSJason Gunthorpe 	}
19391c3d247eSJason Gunthorpe 
19406b753386SAharon Landau 	if (!mr->mmkey.cache_ent)
1941e6fb246cSJason Gunthorpe 		mlx5_free_priv_descs(mr);
19426b753386SAharon Landau 
194309689703SJason Gunthorpe 	kfree(mr);
1944eeea6953SLeon Romanovsky 	return 0;
1945fbcd4983SIlya Lesokhin }
1946fbcd4983SIlya Lesokhin 
mlx5_set_umr_free_mkey(struct ib_pd * pd,u32 * in,int ndescs,int access_mode,int page_shift)19477796d2a3SMax Gurtovoy static void mlx5_set_umr_free_mkey(struct ib_pd *pd, u32 *in, int ndescs,
19487796d2a3SMax Gurtovoy 				   int access_mode, int page_shift)
19497796d2a3SMax Gurtovoy {
19507796d2a3SMax Gurtovoy 	void *mkc;
19517796d2a3SMax Gurtovoy 
19527796d2a3SMax Gurtovoy 	mkc = MLX5_ADDR_OF(create_mkey_in, in, memory_key_mkey_entry);
19537796d2a3SMax Gurtovoy 
19548383da3eSJason Gunthorpe 	/* This is only used from the kernel, so setting the PD is OK. */
19551477d44cSAvihai Horon 	set_mkc_access_pd_addr_fields(mkc, IB_ACCESS_RELAXED_ORDERING, 0, pd);
19567796d2a3SMax Gurtovoy 	MLX5_SET(mkc, mkc, free, 1);
19577796d2a3SMax Gurtovoy 	MLX5_SET(mkc, mkc, translations_octword_size, ndescs);
19587796d2a3SMax Gurtovoy 	MLX5_SET(mkc, mkc, access_mode_1_0, access_mode & 0x3);
19597796d2a3SMax Gurtovoy 	MLX5_SET(mkc, mkc, access_mode_4_2, (access_mode >> 2) & 0x7);
19607796d2a3SMax Gurtovoy 	MLX5_SET(mkc, mkc, umr_en, 1);
19617796d2a3SMax Gurtovoy 	MLX5_SET(mkc, mkc, log_page_size, page_shift);
19627796d2a3SMax Gurtovoy }
19637796d2a3SMax Gurtovoy 
_mlx5_alloc_mkey_descs(struct ib_pd * pd,struct mlx5_ib_mr * mr,int ndescs,int desc_size,int page_shift,int access_mode,u32 * in,int inlen)19647796d2a3SMax Gurtovoy static int _mlx5_alloc_mkey_descs(struct ib_pd *pd, struct mlx5_ib_mr *mr,
19657796d2a3SMax Gurtovoy 				  int ndescs, int desc_size, int page_shift,
19667796d2a3SMax Gurtovoy 				  int access_mode, u32 *in, int inlen)
19677796d2a3SMax Gurtovoy {
19687796d2a3SMax Gurtovoy 	struct mlx5_ib_dev *dev = to_mdev(pd->device);
19697796d2a3SMax Gurtovoy 	int err;
19707796d2a3SMax Gurtovoy 
19717796d2a3SMax Gurtovoy 	mr->access_mode = access_mode;
19727796d2a3SMax Gurtovoy 	mr->desc_size = desc_size;
19737796d2a3SMax Gurtovoy 	mr->max_descs = ndescs;
19747796d2a3SMax Gurtovoy 
19757796d2a3SMax Gurtovoy 	err = mlx5_alloc_priv_descs(pd->device, mr, ndescs, desc_size);
19767796d2a3SMax Gurtovoy 	if (err)
19777796d2a3SMax Gurtovoy 		return err;
19787796d2a3SMax Gurtovoy 
19797796d2a3SMax Gurtovoy 	mlx5_set_umr_free_mkey(pd, in, ndescs, access_mode, page_shift);
19807796d2a3SMax Gurtovoy 
1981fc6a9f86SSaeed Mahameed 	err = mlx5_ib_create_mkey(dev, &mr->mmkey, in, inlen);
19827796d2a3SMax Gurtovoy 	if (err)
19837796d2a3SMax Gurtovoy 		goto err_free_descs;
19847796d2a3SMax Gurtovoy 
19857796d2a3SMax Gurtovoy 	mr->mmkey.type = MLX5_MKEY_MR;
19867796d2a3SMax Gurtovoy 	mr->ibmr.lkey = mr->mmkey.key;
19877796d2a3SMax Gurtovoy 	mr->ibmr.rkey = mr->mmkey.key;
19887796d2a3SMax Gurtovoy 
19897796d2a3SMax Gurtovoy 	return 0;
19907796d2a3SMax Gurtovoy 
19917796d2a3SMax Gurtovoy err_free_descs:
19927796d2a3SMax Gurtovoy 	mlx5_free_priv_descs(mr);
19937796d2a3SMax Gurtovoy 	return err;
19947796d2a3SMax Gurtovoy }
19957796d2a3SMax Gurtovoy 
mlx5_ib_alloc_pi_mr(struct ib_pd * pd,u32 max_num_sg,u32 max_num_meta_sg,int desc_size,int access_mode)19966c984472SMax Gurtovoy static struct mlx5_ib_mr *mlx5_ib_alloc_pi_mr(struct ib_pd *pd,
1997de0ae958SIsrael Rukshin 				u32 max_num_sg, u32 max_num_meta_sg,
1998de0ae958SIsrael Rukshin 				int desc_size, int access_mode)
19993121e3c4SSagi Grimberg {
2000ec22eb53SSaeed Mahameed 	int inlen = MLX5_ST_SZ_BYTES(create_mkey_in);
20016c984472SMax Gurtovoy 	int ndescs = ALIGN(max_num_sg + max_num_meta_sg, 4);
20027796d2a3SMax Gurtovoy 	int page_shift = 0;
2003ec22eb53SSaeed Mahameed 	struct mlx5_ib_mr *mr;
2004ec22eb53SSaeed Mahameed 	u32 *in;
2005b005d316SSagi Grimberg 	int err;
20063121e3c4SSagi Grimberg 
20073121e3c4SSagi Grimberg 	mr = kzalloc(sizeof(*mr), GFP_KERNEL);
20083121e3c4SSagi Grimberg 	if (!mr)
20093121e3c4SSagi Grimberg 		return ERR_PTR(-ENOMEM);
20103121e3c4SSagi Grimberg 
20117796d2a3SMax Gurtovoy 	mr->ibmr.pd = pd;
20127796d2a3SMax Gurtovoy 	mr->ibmr.device = pd->device;
20137796d2a3SMax Gurtovoy 
2014ec22eb53SSaeed Mahameed 	in = kzalloc(inlen, GFP_KERNEL);
20153121e3c4SSagi Grimberg 	if (!in) {
20163121e3c4SSagi Grimberg 		err = -ENOMEM;
20173121e3c4SSagi Grimberg 		goto err_free;
20183121e3c4SSagi Grimberg 	}
20193121e3c4SSagi Grimberg 
2020de0ae958SIsrael Rukshin 	if (access_mode == MLX5_MKC_ACCESS_MODE_MTT)
20217796d2a3SMax Gurtovoy 		page_shift = PAGE_SHIFT;
20223121e3c4SSagi Grimberg 
20237796d2a3SMax Gurtovoy 	err = _mlx5_alloc_mkey_descs(pd, mr, ndescs, desc_size, page_shift,
20247796d2a3SMax Gurtovoy 				     access_mode, in, inlen);
20256c984472SMax Gurtovoy 	if (err)
20266c984472SMax Gurtovoy 		goto err_free_in;
20276c984472SMax Gurtovoy 
20284163cb3dSMaor Gottlieb 	mr->umem = NULL;
20296c984472SMax Gurtovoy 	kfree(in);
20306c984472SMax Gurtovoy 
20316c984472SMax Gurtovoy 	return mr;
20326c984472SMax Gurtovoy 
20336c984472SMax Gurtovoy err_free_in:
20346c984472SMax Gurtovoy 	kfree(in);
20356c984472SMax Gurtovoy err_free:
20366c984472SMax Gurtovoy 	kfree(mr);
20376c984472SMax Gurtovoy 	return ERR_PTR(err);
20386c984472SMax Gurtovoy }
20396c984472SMax Gurtovoy 
mlx5_alloc_mem_reg_descs(struct ib_pd * pd,struct mlx5_ib_mr * mr,int ndescs,u32 * in,int inlen)20407796d2a3SMax Gurtovoy static int mlx5_alloc_mem_reg_descs(struct ib_pd *pd, struct mlx5_ib_mr *mr,
20417796d2a3SMax Gurtovoy 				    int ndescs, u32 *in, int inlen)
20427796d2a3SMax Gurtovoy {
20437796d2a3SMax Gurtovoy 	return _mlx5_alloc_mkey_descs(pd, mr, ndescs, sizeof(struct mlx5_mtt),
20447796d2a3SMax Gurtovoy 				      PAGE_SHIFT, MLX5_MKC_ACCESS_MODE_MTT, in,
20457796d2a3SMax Gurtovoy 				      inlen);
20467796d2a3SMax Gurtovoy }
20477796d2a3SMax Gurtovoy 
mlx5_alloc_sg_gaps_descs(struct ib_pd * pd,struct mlx5_ib_mr * mr,int ndescs,u32 * in,int inlen)20487796d2a3SMax Gurtovoy static int mlx5_alloc_sg_gaps_descs(struct ib_pd *pd, struct mlx5_ib_mr *mr,
20497796d2a3SMax Gurtovoy 				    int ndescs, u32 *in, int inlen)
20507796d2a3SMax Gurtovoy {
20517796d2a3SMax Gurtovoy 	return _mlx5_alloc_mkey_descs(pd, mr, ndescs, sizeof(struct mlx5_klm),
20527796d2a3SMax Gurtovoy 				      0, MLX5_MKC_ACCESS_MODE_KLMS, in, inlen);
20537796d2a3SMax Gurtovoy }
20547796d2a3SMax Gurtovoy 
mlx5_alloc_integrity_descs(struct ib_pd * pd,struct mlx5_ib_mr * mr,int max_num_sg,int max_num_meta_sg,u32 * in,int inlen)20557796d2a3SMax Gurtovoy static int mlx5_alloc_integrity_descs(struct ib_pd *pd, struct mlx5_ib_mr *mr,
20567796d2a3SMax Gurtovoy 				      int max_num_sg, int max_num_meta_sg,
20577796d2a3SMax Gurtovoy 				      u32 *in, int inlen)
20587796d2a3SMax Gurtovoy {
20597796d2a3SMax Gurtovoy 	struct mlx5_ib_dev *dev = to_mdev(pd->device);
20607796d2a3SMax Gurtovoy 	u32 psv_index[2];
20617796d2a3SMax Gurtovoy 	void *mkc;
20627796d2a3SMax Gurtovoy 	int err;
20637796d2a3SMax Gurtovoy 
20647796d2a3SMax Gurtovoy 	mr->sig = kzalloc(sizeof(*mr->sig), GFP_KERNEL);
20657796d2a3SMax Gurtovoy 	if (!mr->sig)
20667796d2a3SMax Gurtovoy 		return -ENOMEM;
20677796d2a3SMax Gurtovoy 
20687796d2a3SMax Gurtovoy 	/* create mem & wire PSVs */
20697796d2a3SMax Gurtovoy 	err = mlx5_core_create_psv(dev->mdev, to_mpd(pd)->pdn, 2, psv_index);
20707796d2a3SMax Gurtovoy 	if (err)
20717796d2a3SMax Gurtovoy 		goto err_free_sig;
20727796d2a3SMax Gurtovoy 
20737796d2a3SMax Gurtovoy 	mr->sig->psv_memory.psv_idx = psv_index[0];
20747796d2a3SMax Gurtovoy 	mr->sig->psv_wire.psv_idx = psv_index[1];
20757796d2a3SMax Gurtovoy 
20767796d2a3SMax Gurtovoy 	mr->sig->sig_status_checked = true;
20777796d2a3SMax Gurtovoy 	mr->sig->sig_err_exists = false;
20787796d2a3SMax Gurtovoy 	/* Next UMR, Arm SIGERR */
20797796d2a3SMax Gurtovoy 	++mr->sig->sigerr_count;
20807796d2a3SMax Gurtovoy 	mr->klm_mr = mlx5_ib_alloc_pi_mr(pd, max_num_sg, max_num_meta_sg,
20817796d2a3SMax Gurtovoy 					 sizeof(struct mlx5_klm),
20827796d2a3SMax Gurtovoy 					 MLX5_MKC_ACCESS_MODE_KLMS);
20837796d2a3SMax Gurtovoy 	if (IS_ERR(mr->klm_mr)) {
20847796d2a3SMax Gurtovoy 		err = PTR_ERR(mr->klm_mr);
20857796d2a3SMax Gurtovoy 		goto err_destroy_psv;
20867796d2a3SMax Gurtovoy 	}
20877796d2a3SMax Gurtovoy 	mr->mtt_mr = mlx5_ib_alloc_pi_mr(pd, max_num_sg, max_num_meta_sg,
20887796d2a3SMax Gurtovoy 					 sizeof(struct mlx5_mtt),
20897796d2a3SMax Gurtovoy 					 MLX5_MKC_ACCESS_MODE_MTT);
20907796d2a3SMax Gurtovoy 	if (IS_ERR(mr->mtt_mr)) {
20917796d2a3SMax Gurtovoy 		err = PTR_ERR(mr->mtt_mr);
20927796d2a3SMax Gurtovoy 		goto err_free_klm_mr;
20937796d2a3SMax Gurtovoy 	}
20947796d2a3SMax Gurtovoy 
20957796d2a3SMax Gurtovoy 	/* Set bsf descriptors for mkey */
20967796d2a3SMax Gurtovoy 	mkc = MLX5_ADDR_OF(create_mkey_in, in, memory_key_mkey_entry);
20977796d2a3SMax Gurtovoy 	MLX5_SET(mkc, mkc, bsf_en, 1);
20987796d2a3SMax Gurtovoy 	MLX5_SET(mkc, mkc, bsf_octword_size, MLX5_MKEY_BSF_OCTO_SIZE);
20997796d2a3SMax Gurtovoy 
21007796d2a3SMax Gurtovoy 	err = _mlx5_alloc_mkey_descs(pd, mr, 4, sizeof(struct mlx5_klm), 0,
21017796d2a3SMax Gurtovoy 				     MLX5_MKC_ACCESS_MODE_KLMS, in, inlen);
21027796d2a3SMax Gurtovoy 	if (err)
21037796d2a3SMax Gurtovoy 		goto err_free_mtt_mr;
21047796d2a3SMax Gurtovoy 
210550211ec9SJason Gunthorpe 	err = xa_err(xa_store(&dev->sig_mrs, mlx5_base_mkey(mr->mmkey.key),
210650211ec9SJason Gunthorpe 			      mr->sig, GFP_KERNEL));
210750211ec9SJason Gunthorpe 	if (err)
210850211ec9SJason Gunthorpe 		goto err_free_descs;
21097796d2a3SMax Gurtovoy 	return 0;
21107796d2a3SMax Gurtovoy 
211150211ec9SJason Gunthorpe err_free_descs:
211250211ec9SJason Gunthorpe 	destroy_mkey(dev, mr);
211350211ec9SJason Gunthorpe 	mlx5_free_priv_descs(mr);
21147796d2a3SMax Gurtovoy err_free_mtt_mr:
2115e6fb246cSJason Gunthorpe 	mlx5_ib_dereg_mr(&mr->mtt_mr->ibmr, NULL);
21167796d2a3SMax Gurtovoy 	mr->mtt_mr = NULL;
21177796d2a3SMax Gurtovoy err_free_klm_mr:
2118e6fb246cSJason Gunthorpe 	mlx5_ib_dereg_mr(&mr->klm_mr->ibmr, NULL);
21197796d2a3SMax Gurtovoy 	mr->klm_mr = NULL;
21207796d2a3SMax Gurtovoy err_destroy_psv:
21217796d2a3SMax Gurtovoy 	if (mlx5_core_destroy_psv(dev->mdev, mr->sig->psv_memory.psv_idx))
21227796d2a3SMax Gurtovoy 		mlx5_ib_warn(dev, "failed to destroy mem psv %d\n",
21237796d2a3SMax Gurtovoy 			     mr->sig->psv_memory.psv_idx);
21247796d2a3SMax Gurtovoy 	if (mlx5_core_destroy_psv(dev->mdev, mr->sig->psv_wire.psv_idx))
21257796d2a3SMax Gurtovoy 		mlx5_ib_warn(dev, "failed to destroy wire psv %d\n",
21267796d2a3SMax Gurtovoy 			     mr->sig->psv_wire.psv_idx);
21277796d2a3SMax Gurtovoy err_free_sig:
21287796d2a3SMax Gurtovoy 	kfree(mr->sig);
21297796d2a3SMax Gurtovoy 
21307796d2a3SMax Gurtovoy 	return err;
21317796d2a3SMax Gurtovoy }
21327796d2a3SMax Gurtovoy 
__mlx5_ib_alloc_mr(struct ib_pd * pd,enum ib_mr_type mr_type,u32 max_num_sg,u32 max_num_meta_sg)21336c984472SMax Gurtovoy static struct ib_mr *__mlx5_ib_alloc_mr(struct ib_pd *pd,
21346c984472SMax Gurtovoy 					enum ib_mr_type mr_type, u32 max_num_sg,
21356c984472SMax Gurtovoy 					u32 max_num_meta_sg)
21366c984472SMax Gurtovoy {
21376c984472SMax Gurtovoy 	struct mlx5_ib_dev *dev = to_mdev(pd->device);
21386c984472SMax Gurtovoy 	int inlen = MLX5_ST_SZ_BYTES(create_mkey_in);
21396c984472SMax Gurtovoy 	int ndescs = ALIGN(max_num_sg, 4);
21406c984472SMax Gurtovoy 	struct mlx5_ib_mr *mr;
21416c984472SMax Gurtovoy 	u32 *in;
21426c984472SMax Gurtovoy 	int err;
21436c984472SMax Gurtovoy 
21446c984472SMax Gurtovoy 	mr = kzalloc(sizeof(*mr), GFP_KERNEL);
21456c984472SMax Gurtovoy 	if (!mr)
21466c984472SMax Gurtovoy 		return ERR_PTR(-ENOMEM);
21476c984472SMax Gurtovoy 
21486c984472SMax Gurtovoy 	in = kzalloc(inlen, GFP_KERNEL);
21496c984472SMax Gurtovoy 	if (!in) {
21506c984472SMax Gurtovoy 		err = -ENOMEM;
21516c984472SMax Gurtovoy 		goto err_free;
21526c984472SMax Gurtovoy 	}
21536c984472SMax Gurtovoy 
21547796d2a3SMax Gurtovoy 	mr->ibmr.device = pd->device;
21554163cb3dSMaor Gottlieb 	mr->umem = NULL;
21566c984472SMax Gurtovoy 
21577796d2a3SMax Gurtovoy 	switch (mr_type) {
21587796d2a3SMax Gurtovoy 	case IB_MR_TYPE_MEM_REG:
21597796d2a3SMax Gurtovoy 		err = mlx5_alloc_mem_reg_descs(pd, mr, ndescs, in, inlen);
21607796d2a3SMax Gurtovoy 		break;
21617796d2a3SMax Gurtovoy 	case IB_MR_TYPE_SG_GAPS:
21627796d2a3SMax Gurtovoy 		err = mlx5_alloc_sg_gaps_descs(pd, mr, ndescs, in, inlen);
21637796d2a3SMax Gurtovoy 		break;
21647796d2a3SMax Gurtovoy 	case IB_MR_TYPE_INTEGRITY:
21657796d2a3SMax Gurtovoy 		err = mlx5_alloc_integrity_descs(pd, mr, max_num_sg,
21667796d2a3SMax Gurtovoy 						 max_num_meta_sg, in, inlen);
21677796d2a3SMax Gurtovoy 		break;
21687796d2a3SMax Gurtovoy 	default:
21699bee178bSSagi Grimberg 		mlx5_ib_warn(dev, "Invalid mr type %d\n", mr_type);
21709bee178bSSagi Grimberg 		err = -EINVAL;
21713121e3c4SSagi Grimberg 	}
21723121e3c4SSagi Grimberg 
21733121e3c4SSagi Grimberg 	if (err)
21747796d2a3SMax Gurtovoy 		goto err_free_in;
21753121e3c4SSagi Grimberg 
21763121e3c4SSagi Grimberg 	kfree(in);
21773121e3c4SSagi Grimberg 
21783121e3c4SSagi Grimberg 	return &mr->ibmr;
21793121e3c4SSagi Grimberg 
21803121e3c4SSagi Grimberg err_free_in:
21813121e3c4SSagi Grimberg 	kfree(in);
21823121e3c4SSagi Grimberg err_free:
21833121e3c4SSagi Grimberg 	kfree(mr);
21843121e3c4SSagi Grimberg 	return ERR_PTR(err);
21853121e3c4SSagi Grimberg }
21863121e3c4SSagi Grimberg 
mlx5_ib_alloc_mr(struct ib_pd * pd,enum ib_mr_type mr_type,u32 max_num_sg)21876c984472SMax Gurtovoy struct ib_mr *mlx5_ib_alloc_mr(struct ib_pd *pd, enum ib_mr_type mr_type,
218842a3b153SGal Pressman 			       u32 max_num_sg)
21896c984472SMax Gurtovoy {
21906c984472SMax Gurtovoy 	return __mlx5_ib_alloc_mr(pd, mr_type, max_num_sg, 0);
21916c984472SMax Gurtovoy }
21926c984472SMax Gurtovoy 
mlx5_ib_alloc_mr_integrity(struct ib_pd * pd,u32 max_num_sg,u32 max_num_meta_sg)21936c984472SMax Gurtovoy struct ib_mr *mlx5_ib_alloc_mr_integrity(struct ib_pd *pd,
21946c984472SMax Gurtovoy 					 u32 max_num_sg, u32 max_num_meta_sg)
21956c984472SMax Gurtovoy {
21966c984472SMax Gurtovoy 	return __mlx5_ib_alloc_mr(pd, IB_MR_TYPE_INTEGRITY, max_num_sg,
21976c984472SMax Gurtovoy 				  max_num_meta_sg);
21986c984472SMax Gurtovoy }
21996c984472SMax Gurtovoy 
mlx5_ib_alloc_mw(struct ib_mw * ibmw,struct ib_udata * udata)2200d18bb3e1SLeon Romanovsky int mlx5_ib_alloc_mw(struct ib_mw *ibmw, struct ib_udata *udata)
2201d2370e0aSMatan Barak {
2202d18bb3e1SLeon Romanovsky 	struct mlx5_ib_dev *dev = to_mdev(ibmw->device);
2203ec22eb53SSaeed Mahameed 	int inlen = MLX5_ST_SZ_BYTES(create_mkey_in);
2204d18bb3e1SLeon Romanovsky 	struct mlx5_ib_mw *mw = to_mmw(ibmw);
2205ae0579acSAharon Landau 	unsigned int ndescs;
2206ec22eb53SSaeed Mahameed 	u32 *in = NULL;
2207ec22eb53SSaeed Mahameed 	void *mkc;
2208d2370e0aSMatan Barak 	int err;
2209d2370e0aSMatan Barak 	struct mlx5_ib_alloc_mw req = {};
2210d2370e0aSMatan Barak 	struct {
2211d2370e0aSMatan Barak 		__u32	comp_mask;
2212d2370e0aSMatan Barak 		__u32	response_length;
2213d2370e0aSMatan Barak 	} resp = {};
2214d2370e0aSMatan Barak 
2215d2370e0aSMatan Barak 	err = ib_copy_from_udata(&req, udata, min(udata->inlen, sizeof(req)));
2216d2370e0aSMatan Barak 	if (err)
2217d18bb3e1SLeon Romanovsky 		return err;
2218d2370e0aSMatan Barak 
2219d2370e0aSMatan Barak 	if (req.comp_mask || req.reserved1 || req.reserved2)
2220d18bb3e1SLeon Romanovsky 		return -EOPNOTSUPP;
2221d2370e0aSMatan Barak 
2222d2370e0aSMatan Barak 	if (udata->inlen > sizeof(req) &&
2223d2370e0aSMatan Barak 	    !ib_is_udata_cleared(udata, sizeof(req),
2224d2370e0aSMatan Barak 				 udata->inlen - sizeof(req)))
2225d18bb3e1SLeon Romanovsky 		return -EOPNOTSUPP;
2226d2370e0aSMatan Barak 
2227d2370e0aSMatan Barak 	ndescs = req.num_klms ? roundup(req.num_klms, 4) : roundup(1, 4);
2228d2370e0aSMatan Barak 
2229ec22eb53SSaeed Mahameed 	in = kzalloc(inlen, GFP_KERNEL);
22306978837cSLi Zhijian 	if (!in)
22316978837cSLi Zhijian 		return -ENOMEM;
2232d2370e0aSMatan Barak 
2233ec22eb53SSaeed Mahameed 	mkc = MLX5_ADDR_OF(create_mkey_in, in, memory_key_mkey_entry);
2234d2370e0aSMatan Barak 
2235ec22eb53SSaeed Mahameed 	MLX5_SET(mkc, mkc, free, 1);
2236ec22eb53SSaeed Mahameed 	MLX5_SET(mkc, mkc, translations_octword_size, ndescs);
2237d18bb3e1SLeon Romanovsky 	MLX5_SET(mkc, mkc, pd, to_mpd(ibmw->pd)->pdn);
2238ec22eb53SSaeed Mahameed 	MLX5_SET(mkc, mkc, umr_en, 1);
2239ec22eb53SSaeed Mahameed 	MLX5_SET(mkc, mkc, lr, 1);
2240cdbd0d2bSAriel Levkovich 	MLX5_SET(mkc, mkc, access_mode_1_0, MLX5_MKC_ACCESS_MODE_KLMS);
2241d18bb3e1SLeon Romanovsky 	MLX5_SET(mkc, mkc, en_rinval, !!((ibmw->type == IB_MW_TYPE_2)));
2242ec22eb53SSaeed Mahameed 	MLX5_SET(mkc, mkc, qpn, 0xffffff);
2243ec22eb53SSaeed Mahameed 
2244fc6a9f86SSaeed Mahameed 	err = mlx5_ib_create_mkey(dev, &mw->mmkey, in, inlen);
2245d2370e0aSMatan Barak 	if (err)
2246d2370e0aSMatan Barak 		goto free;
2247d2370e0aSMatan Barak 
2248aa8e08d2SArtemy Kovalyov 	mw->mmkey.type = MLX5_MKEY_MW;
2249d18bb3e1SLeon Romanovsky 	ibmw->rkey = mw->mmkey.key;
2250ae0579acSAharon Landau 	mw->mmkey.ndescs = ndescs;
2251d2370e0aSMatan Barak 
225270c1430fSLeon Romanovsky 	resp.response_length =
225370c1430fSLeon Romanovsky 		min(offsetofend(typeof(resp), response_length), udata->outlen);
2254d2370e0aSMatan Barak 	if (resp.response_length) {
2255d2370e0aSMatan Barak 		err = ib_copy_to_udata(udata, &resp, resp.response_length);
2256d18bb3e1SLeon Romanovsky 		if (err)
2257d18bb3e1SLeon Romanovsky 			goto free_mkey;
2258d2370e0aSMatan Barak 	}
2259d2370e0aSMatan Barak 
2260806b101bSJason Gunthorpe 	if (IS_ENABLED(CONFIG_INFINIBAND_ON_DEMAND_PAGING)) {
2261db72438cSYishai Hadas 		err = mlx5r_store_odp_mkey(dev, &mw->mmkey);
2262806b101bSJason Gunthorpe 		if (err)
2263806b101bSJason Gunthorpe 			goto free_mkey;
2264806b101bSJason Gunthorpe 	}
2265806b101bSJason Gunthorpe 
2266d2370e0aSMatan Barak 	kfree(in);
2267d18bb3e1SLeon Romanovsky 	return 0;
2268d2370e0aSMatan Barak 
2269806b101bSJason Gunthorpe free_mkey:
227083fec3f1SAharon Landau 	mlx5_core_destroy_mkey(dev->mdev, mw->mmkey.key);
2271d2370e0aSMatan Barak free:
2272d2370e0aSMatan Barak 	kfree(in);
2273d18bb3e1SLeon Romanovsky 	return err;
2274d2370e0aSMatan Barak }
2275d2370e0aSMatan Barak 
mlx5_ib_dealloc_mw(struct ib_mw * mw)2276d2370e0aSMatan Barak int mlx5_ib_dealloc_mw(struct ib_mw *mw)
2277d2370e0aSMatan Barak {
227804177915SJason Gunthorpe 	struct mlx5_ib_dev *dev = to_mdev(mw->device);
2279d2370e0aSMatan Barak 	struct mlx5_ib_mw *mmw = to_mmw(mw);
2280d2370e0aSMatan Barak 
2281db72438cSYishai Hadas 	if (IS_ENABLED(CONFIG_INFINIBAND_ON_DEMAND_PAGING) &&
2282db72438cSYishai Hadas 	    xa_erase(&dev->odp_mkeys, mlx5_base_mkey(mmw->mmkey.key)))
228304177915SJason Gunthorpe 		/*
2284db72438cSYishai Hadas 		 * pagefault_single_data_segment() may be accessing mmw
2285db72438cSYishai Hadas 		 * if the user bound an ODP MR to this MW.
228604177915SJason Gunthorpe 		 */
2287db72438cSYishai Hadas 		mlx5r_deref_wait_odp_mkey(&mmw->mmkey);
228804177915SJason Gunthorpe 
228983fec3f1SAharon Landau 	return mlx5_core_destroy_mkey(dev->mdev, mmw->mmkey.key);
2290d2370e0aSMatan Barak }
2291d2370e0aSMatan Barak 
mlx5_ib_check_mr_status(struct ib_mr * ibmr,u32 check_mask,struct ib_mr_status * mr_status)2292d5436ba0SSagi Grimberg int mlx5_ib_check_mr_status(struct ib_mr *ibmr, u32 check_mask,
2293d5436ba0SSagi Grimberg 			    struct ib_mr_status *mr_status)
2294d5436ba0SSagi Grimberg {
2295d5436ba0SSagi Grimberg 	struct mlx5_ib_mr *mmr = to_mmr(ibmr);
2296d5436ba0SSagi Grimberg 	int ret = 0;
2297d5436ba0SSagi Grimberg 
2298d5436ba0SSagi Grimberg 	if (check_mask & ~IB_MR_CHECK_SIG_STATUS) {
2299d5436ba0SSagi Grimberg 		pr_err("Invalid status check mask\n");
2300d5436ba0SSagi Grimberg 		ret = -EINVAL;
2301d5436ba0SSagi Grimberg 		goto done;
2302d5436ba0SSagi Grimberg 	}
2303d5436ba0SSagi Grimberg 
2304d5436ba0SSagi Grimberg 	mr_status->fail_status = 0;
2305d5436ba0SSagi Grimberg 	if (check_mask & IB_MR_CHECK_SIG_STATUS) {
2306d5436ba0SSagi Grimberg 		if (!mmr->sig) {
2307d5436ba0SSagi Grimberg 			ret = -EINVAL;
2308d5436ba0SSagi Grimberg 			pr_err("signature status check requested on a non-signature enabled MR\n");
2309d5436ba0SSagi Grimberg 			goto done;
2310d5436ba0SSagi Grimberg 		}
2311d5436ba0SSagi Grimberg 
2312d5436ba0SSagi Grimberg 		mmr->sig->sig_status_checked = true;
2313d5436ba0SSagi Grimberg 		if (!mmr->sig->sig_err_exists)
2314d5436ba0SSagi Grimberg 			goto done;
2315d5436ba0SSagi Grimberg 
2316d5436ba0SSagi Grimberg 		if (ibmr->lkey == mmr->sig->err_item.key)
2317d5436ba0SSagi Grimberg 			memcpy(&mr_status->sig_err, &mmr->sig->err_item,
2318d5436ba0SSagi Grimberg 			       sizeof(mr_status->sig_err));
2319d5436ba0SSagi Grimberg 		else {
2320d5436ba0SSagi Grimberg 			mr_status->sig_err.err_type = IB_SIG_BAD_GUARD;
2321d5436ba0SSagi Grimberg 			mr_status->sig_err.sig_err_offset = 0;
2322d5436ba0SSagi Grimberg 			mr_status->sig_err.key = mmr->sig->err_item.key;
2323d5436ba0SSagi Grimberg 		}
2324d5436ba0SSagi Grimberg 
2325d5436ba0SSagi Grimberg 		mmr->sig->sig_err_exists = false;
2326d5436ba0SSagi Grimberg 		mr_status->fail_status |= IB_MR_CHECK_SIG_STATUS;
2327d5436ba0SSagi Grimberg 	}
2328d5436ba0SSagi Grimberg 
2329d5436ba0SSagi Grimberg done:
2330d5436ba0SSagi Grimberg 	return ret;
2331d5436ba0SSagi Grimberg }
23328a187ee5SSagi Grimberg 
2333b005d316SSagi Grimberg static int
mlx5_ib_map_pa_mr_sg_pi(struct ib_mr * ibmr,struct scatterlist * data_sg,int data_sg_nents,unsigned int * data_sg_offset,struct scatterlist * meta_sg,int meta_sg_nents,unsigned int * meta_sg_offset)23342563e2f3SMax Gurtovoy mlx5_ib_map_pa_mr_sg_pi(struct ib_mr *ibmr, struct scatterlist *data_sg,
23352563e2f3SMax Gurtovoy 			int data_sg_nents, unsigned int *data_sg_offset,
23362563e2f3SMax Gurtovoy 			struct scatterlist *meta_sg, int meta_sg_nents,
23372563e2f3SMax Gurtovoy 			unsigned int *meta_sg_offset)
23382563e2f3SMax Gurtovoy {
23392563e2f3SMax Gurtovoy 	struct mlx5_ib_mr *mr = to_mmr(ibmr);
23402563e2f3SMax Gurtovoy 	unsigned int sg_offset = 0;
23412563e2f3SMax Gurtovoy 	int n = 0;
23422563e2f3SMax Gurtovoy 
23432563e2f3SMax Gurtovoy 	mr->meta_length = 0;
23442563e2f3SMax Gurtovoy 	if (data_sg_nents == 1) {
23452563e2f3SMax Gurtovoy 		n++;
2346ae0579acSAharon Landau 		mr->mmkey.ndescs = 1;
23472563e2f3SMax Gurtovoy 		if (data_sg_offset)
23482563e2f3SMax Gurtovoy 			sg_offset = *data_sg_offset;
23492563e2f3SMax Gurtovoy 		mr->data_length = sg_dma_len(data_sg) - sg_offset;
23502563e2f3SMax Gurtovoy 		mr->data_iova = sg_dma_address(data_sg) + sg_offset;
23512563e2f3SMax Gurtovoy 		if (meta_sg_nents == 1) {
23522563e2f3SMax Gurtovoy 			n++;
23532563e2f3SMax Gurtovoy 			mr->meta_ndescs = 1;
23542563e2f3SMax Gurtovoy 			if (meta_sg_offset)
23552563e2f3SMax Gurtovoy 				sg_offset = *meta_sg_offset;
23562563e2f3SMax Gurtovoy 			else
23572563e2f3SMax Gurtovoy 				sg_offset = 0;
23582563e2f3SMax Gurtovoy 			mr->meta_length = sg_dma_len(meta_sg) - sg_offset;
23592563e2f3SMax Gurtovoy 			mr->pi_iova = sg_dma_address(meta_sg) + sg_offset;
23602563e2f3SMax Gurtovoy 		}
23612563e2f3SMax Gurtovoy 		ibmr->length = mr->data_length + mr->meta_length;
23622563e2f3SMax Gurtovoy 	}
23632563e2f3SMax Gurtovoy 
23642563e2f3SMax Gurtovoy 	return n;
23652563e2f3SMax Gurtovoy }
23662563e2f3SMax Gurtovoy 
23672563e2f3SMax Gurtovoy static int
mlx5_ib_sg_to_klms(struct mlx5_ib_mr * mr,struct scatterlist * sgl,unsigned short sg_nents,unsigned int * sg_offset_p,struct scatterlist * meta_sgl,unsigned short meta_sg_nents,unsigned int * meta_sg_offset_p)2368b005d316SSagi Grimberg mlx5_ib_sg_to_klms(struct mlx5_ib_mr *mr,
2369b005d316SSagi Grimberg 		   struct scatterlist *sgl,
2370ff2ba993SChristoph Hellwig 		   unsigned short sg_nents,
23716c984472SMax Gurtovoy 		   unsigned int *sg_offset_p,
23726c984472SMax Gurtovoy 		   struct scatterlist *meta_sgl,
23736c984472SMax Gurtovoy 		   unsigned short meta_sg_nents,
23746c984472SMax Gurtovoy 		   unsigned int *meta_sg_offset_p)
2375b005d316SSagi Grimberg {
2376b005d316SSagi Grimberg 	struct scatterlist *sg = sgl;
2377b005d316SSagi Grimberg 	struct mlx5_klm *klms = mr->descs;
23789aa8b321SBart Van Assche 	unsigned int sg_offset = sg_offset_p ? *sg_offset_p : 0;
2379b005d316SSagi Grimberg 	u32 lkey = mr->ibmr.pd->local_dma_lkey;
23806c984472SMax Gurtovoy 	int i, j = 0;
2381b005d316SSagi Grimberg 
2382ff2ba993SChristoph Hellwig 	mr->ibmr.iova = sg_dma_address(sg) + sg_offset;
2383b005d316SSagi Grimberg 	mr->ibmr.length = 0;
2384b005d316SSagi Grimberg 
2385b005d316SSagi Grimberg 	for_each_sg(sgl, sg, sg_nents, i) {
238699975cd4SBart Van Assche 		if (unlikely(i >= mr->max_descs))
2387b005d316SSagi Grimberg 			break;
2388ff2ba993SChristoph Hellwig 		klms[i].va = cpu_to_be64(sg_dma_address(sg) + sg_offset);
2389ff2ba993SChristoph Hellwig 		klms[i].bcount = cpu_to_be32(sg_dma_len(sg) - sg_offset);
2390b005d316SSagi Grimberg 		klms[i].key = cpu_to_be32(lkey);
23910a49f2c3SSagi Grimberg 		mr->ibmr.length += sg_dma_len(sg) - sg_offset;
2392ff2ba993SChristoph Hellwig 
2393ff2ba993SChristoph Hellwig 		sg_offset = 0;
2394b005d316SSagi Grimberg 	}
2395b005d316SSagi Grimberg 
23969aa8b321SBart Van Assche 	if (sg_offset_p)
23979aa8b321SBart Van Assche 		*sg_offset_p = sg_offset;
23989aa8b321SBart Van Assche 
2399ae0579acSAharon Landau 	mr->mmkey.ndescs = i;
24006c984472SMax Gurtovoy 	mr->data_length = mr->ibmr.length;
24016c984472SMax Gurtovoy 
24026c984472SMax Gurtovoy 	if (meta_sg_nents) {
24036c984472SMax Gurtovoy 		sg = meta_sgl;
24046c984472SMax Gurtovoy 		sg_offset = meta_sg_offset_p ? *meta_sg_offset_p : 0;
24056c984472SMax Gurtovoy 		for_each_sg(meta_sgl, sg, meta_sg_nents, j) {
24066c984472SMax Gurtovoy 			if (unlikely(i + j >= mr->max_descs))
24076c984472SMax Gurtovoy 				break;
24086c984472SMax Gurtovoy 			klms[i + j].va = cpu_to_be64(sg_dma_address(sg) +
24096c984472SMax Gurtovoy 						     sg_offset);
24106c984472SMax Gurtovoy 			klms[i + j].bcount = cpu_to_be32(sg_dma_len(sg) -
24116c984472SMax Gurtovoy 							 sg_offset);
24126c984472SMax Gurtovoy 			klms[i + j].key = cpu_to_be32(lkey);
24136c984472SMax Gurtovoy 			mr->ibmr.length += sg_dma_len(sg) - sg_offset;
24146c984472SMax Gurtovoy 
24156c984472SMax Gurtovoy 			sg_offset = 0;
24166c984472SMax Gurtovoy 		}
24176c984472SMax Gurtovoy 		if (meta_sg_offset_p)
24186c984472SMax Gurtovoy 			*meta_sg_offset_p = sg_offset;
24196c984472SMax Gurtovoy 
24206c984472SMax Gurtovoy 		mr->meta_ndescs = j;
24216c984472SMax Gurtovoy 		mr->meta_length = mr->ibmr.length - mr->data_length;
24226c984472SMax Gurtovoy 	}
24236c984472SMax Gurtovoy 
24246c984472SMax Gurtovoy 	return i + j;
2425b005d316SSagi Grimberg }
2426b005d316SSagi Grimberg 
mlx5_set_page(struct ib_mr * ibmr,u64 addr)24278a187ee5SSagi Grimberg static int mlx5_set_page(struct ib_mr *ibmr, u64 addr)
24288a187ee5SSagi Grimberg {
24298a187ee5SSagi Grimberg 	struct mlx5_ib_mr *mr = to_mmr(ibmr);
24308a187ee5SSagi Grimberg 	__be64 *descs;
24318a187ee5SSagi Grimberg 
2432ae0579acSAharon Landau 	if (unlikely(mr->mmkey.ndescs == mr->max_descs))
24338a187ee5SSagi Grimberg 		return -ENOMEM;
24348a187ee5SSagi Grimberg 
24358a187ee5SSagi Grimberg 	descs = mr->descs;
2436ae0579acSAharon Landau 	descs[mr->mmkey.ndescs++] = cpu_to_be64(addr | MLX5_EN_RD | MLX5_EN_WR);
24378a187ee5SSagi Grimberg 
24388a187ee5SSagi Grimberg 	return 0;
24398a187ee5SSagi Grimberg }
24408a187ee5SSagi Grimberg 
mlx5_set_page_pi(struct ib_mr * ibmr,u64 addr)2441de0ae958SIsrael Rukshin static int mlx5_set_page_pi(struct ib_mr *ibmr, u64 addr)
2442de0ae958SIsrael Rukshin {
2443de0ae958SIsrael Rukshin 	struct mlx5_ib_mr *mr = to_mmr(ibmr);
2444de0ae958SIsrael Rukshin 	__be64 *descs;
2445de0ae958SIsrael Rukshin 
2446ae0579acSAharon Landau 	if (unlikely(mr->mmkey.ndescs + mr->meta_ndescs == mr->max_descs))
2447de0ae958SIsrael Rukshin 		return -ENOMEM;
2448de0ae958SIsrael Rukshin 
2449de0ae958SIsrael Rukshin 	descs = mr->descs;
2450ae0579acSAharon Landau 	descs[mr->mmkey.ndescs + mr->meta_ndescs++] =
2451de0ae958SIsrael Rukshin 		cpu_to_be64(addr | MLX5_EN_RD | MLX5_EN_WR);
2452de0ae958SIsrael Rukshin 
2453de0ae958SIsrael Rukshin 	return 0;
2454de0ae958SIsrael Rukshin }
2455de0ae958SIsrael Rukshin 
2456de0ae958SIsrael Rukshin static int
mlx5_ib_map_mtt_mr_sg_pi(struct ib_mr * ibmr,struct scatterlist * data_sg,int data_sg_nents,unsigned int * data_sg_offset,struct scatterlist * meta_sg,int meta_sg_nents,unsigned int * meta_sg_offset)2457de0ae958SIsrael Rukshin mlx5_ib_map_mtt_mr_sg_pi(struct ib_mr *ibmr, struct scatterlist *data_sg,
24586c984472SMax Gurtovoy 			 int data_sg_nents, unsigned int *data_sg_offset,
24596c984472SMax Gurtovoy 			 struct scatterlist *meta_sg, int meta_sg_nents,
24606c984472SMax Gurtovoy 			 unsigned int *meta_sg_offset)
24616c984472SMax Gurtovoy {
24626c984472SMax Gurtovoy 	struct mlx5_ib_mr *mr = to_mmr(ibmr);
2463de0ae958SIsrael Rukshin 	struct mlx5_ib_mr *pi_mr = mr->mtt_mr;
24646c984472SMax Gurtovoy 	int n;
24656c984472SMax Gurtovoy 
2466ae0579acSAharon Landau 	pi_mr->mmkey.ndescs = 0;
2467de0ae958SIsrael Rukshin 	pi_mr->meta_ndescs = 0;
2468de0ae958SIsrael Rukshin 	pi_mr->meta_length = 0;
2469de0ae958SIsrael Rukshin 
2470de0ae958SIsrael Rukshin 	ib_dma_sync_single_for_cpu(ibmr->device, pi_mr->desc_map,
2471de0ae958SIsrael Rukshin 				   pi_mr->desc_size * pi_mr->max_descs,
2472de0ae958SIsrael Rukshin 				   DMA_TO_DEVICE);
2473de0ae958SIsrael Rukshin 
2474de0ae958SIsrael Rukshin 	pi_mr->ibmr.page_size = ibmr->page_size;
2475de0ae958SIsrael Rukshin 	n = ib_sg_to_pages(&pi_mr->ibmr, data_sg, data_sg_nents, data_sg_offset,
2476de0ae958SIsrael Rukshin 			   mlx5_set_page);
2477de0ae958SIsrael Rukshin 	if (n != data_sg_nents)
2478de0ae958SIsrael Rukshin 		return n;
2479de0ae958SIsrael Rukshin 
24802563e2f3SMax Gurtovoy 	pi_mr->data_iova = pi_mr->ibmr.iova;
2481de0ae958SIsrael Rukshin 	pi_mr->data_length = pi_mr->ibmr.length;
2482de0ae958SIsrael Rukshin 	pi_mr->ibmr.length = pi_mr->data_length;
2483de0ae958SIsrael Rukshin 	ibmr->length = pi_mr->data_length;
2484de0ae958SIsrael Rukshin 
2485de0ae958SIsrael Rukshin 	if (meta_sg_nents) {
2486de0ae958SIsrael Rukshin 		u64 page_mask = ~((u64)ibmr->page_size - 1);
24872563e2f3SMax Gurtovoy 		u64 iova = pi_mr->data_iova;
2488de0ae958SIsrael Rukshin 
2489de0ae958SIsrael Rukshin 		n += ib_sg_to_pages(&pi_mr->ibmr, meta_sg, meta_sg_nents,
2490de0ae958SIsrael Rukshin 				    meta_sg_offset, mlx5_set_page_pi);
2491de0ae958SIsrael Rukshin 
2492de0ae958SIsrael Rukshin 		pi_mr->meta_length = pi_mr->ibmr.length;
2493de0ae958SIsrael Rukshin 		/*
2494de0ae958SIsrael Rukshin 		 * PI address for the HW is the offset of the metadata address
2495de0ae958SIsrael Rukshin 		 * relative to the first data page address.
2496de0ae958SIsrael Rukshin 		 * It equals to first data page address + size of data pages +
2497de0ae958SIsrael Rukshin 		 * metadata offset at the first metadata page
2498de0ae958SIsrael Rukshin 		 */
2499de0ae958SIsrael Rukshin 		pi_mr->pi_iova = (iova & page_mask) +
2500ae0579acSAharon Landau 				 pi_mr->mmkey.ndescs * ibmr->page_size +
2501de0ae958SIsrael Rukshin 				 (pi_mr->ibmr.iova & ~page_mask);
2502de0ae958SIsrael Rukshin 		/*
2503de0ae958SIsrael Rukshin 		 * In order to use one MTT MR for data and metadata, we register
2504de0ae958SIsrael Rukshin 		 * also the gaps between the end of the data and the start of
2505de0ae958SIsrael Rukshin 		 * the metadata (the sig MR will verify that the HW will access
2506de0ae958SIsrael Rukshin 		 * to right addresses). This mapping is safe because we use
2507de0ae958SIsrael Rukshin 		 * internal mkey for the registration.
2508de0ae958SIsrael Rukshin 		 */
2509de0ae958SIsrael Rukshin 		pi_mr->ibmr.length = pi_mr->pi_iova + pi_mr->meta_length - iova;
2510de0ae958SIsrael Rukshin 		pi_mr->ibmr.iova = iova;
2511de0ae958SIsrael Rukshin 		ibmr->length += pi_mr->meta_length;
2512de0ae958SIsrael Rukshin 	}
2513de0ae958SIsrael Rukshin 
2514de0ae958SIsrael Rukshin 	ib_dma_sync_single_for_device(ibmr->device, pi_mr->desc_map,
2515de0ae958SIsrael Rukshin 				      pi_mr->desc_size * pi_mr->max_descs,
2516de0ae958SIsrael Rukshin 				      DMA_TO_DEVICE);
2517de0ae958SIsrael Rukshin 
2518de0ae958SIsrael Rukshin 	return n;
2519de0ae958SIsrael Rukshin }
2520de0ae958SIsrael Rukshin 
2521de0ae958SIsrael Rukshin static int
mlx5_ib_map_klm_mr_sg_pi(struct ib_mr * ibmr,struct scatterlist * data_sg,int data_sg_nents,unsigned int * data_sg_offset,struct scatterlist * meta_sg,int meta_sg_nents,unsigned int * meta_sg_offset)2522de0ae958SIsrael Rukshin mlx5_ib_map_klm_mr_sg_pi(struct ib_mr *ibmr, struct scatterlist *data_sg,
2523de0ae958SIsrael Rukshin 			 int data_sg_nents, unsigned int *data_sg_offset,
2524de0ae958SIsrael Rukshin 			 struct scatterlist *meta_sg, int meta_sg_nents,
2525de0ae958SIsrael Rukshin 			 unsigned int *meta_sg_offset)
2526de0ae958SIsrael Rukshin {
2527de0ae958SIsrael Rukshin 	struct mlx5_ib_mr *mr = to_mmr(ibmr);
2528de0ae958SIsrael Rukshin 	struct mlx5_ib_mr *pi_mr = mr->klm_mr;
2529de0ae958SIsrael Rukshin 	int n;
25306c984472SMax Gurtovoy 
2531ae0579acSAharon Landau 	pi_mr->mmkey.ndescs = 0;
25326c984472SMax Gurtovoy 	pi_mr->meta_ndescs = 0;
25336c984472SMax Gurtovoy 	pi_mr->meta_length = 0;
25346c984472SMax Gurtovoy 
25356c984472SMax Gurtovoy 	ib_dma_sync_single_for_cpu(ibmr->device, pi_mr->desc_map,
25366c984472SMax Gurtovoy 				   pi_mr->desc_size * pi_mr->max_descs,
25376c984472SMax Gurtovoy 				   DMA_TO_DEVICE);
25386c984472SMax Gurtovoy 
25396c984472SMax Gurtovoy 	n = mlx5_ib_sg_to_klms(pi_mr, data_sg, data_sg_nents, data_sg_offset,
25406c984472SMax Gurtovoy 			       meta_sg, meta_sg_nents, meta_sg_offset);
25416c984472SMax Gurtovoy 
25426c984472SMax Gurtovoy 	ib_dma_sync_single_for_device(ibmr->device, pi_mr->desc_map,
25436c984472SMax Gurtovoy 				      pi_mr->desc_size * pi_mr->max_descs,
25446c984472SMax Gurtovoy 				      DMA_TO_DEVICE);
25456c984472SMax Gurtovoy 
2546de0ae958SIsrael Rukshin 	/* This is zero-based memory region */
25472563e2f3SMax Gurtovoy 	pi_mr->data_iova = 0;
2548de0ae958SIsrael Rukshin 	pi_mr->ibmr.iova = 0;
2549de0ae958SIsrael Rukshin 	pi_mr->pi_iova = pi_mr->data_length;
2550de0ae958SIsrael Rukshin 	ibmr->length = pi_mr->ibmr.length;
2551de0ae958SIsrael Rukshin 
2552de0ae958SIsrael Rukshin 	return n;
2553de0ae958SIsrael Rukshin }
2554de0ae958SIsrael Rukshin 
mlx5_ib_map_mr_sg_pi(struct ib_mr * ibmr,struct scatterlist * data_sg,int data_sg_nents,unsigned int * data_sg_offset,struct scatterlist * meta_sg,int meta_sg_nents,unsigned int * meta_sg_offset)2555de0ae958SIsrael Rukshin int mlx5_ib_map_mr_sg_pi(struct ib_mr *ibmr, struct scatterlist *data_sg,
2556de0ae958SIsrael Rukshin 			 int data_sg_nents, unsigned int *data_sg_offset,
2557de0ae958SIsrael Rukshin 			 struct scatterlist *meta_sg, int meta_sg_nents,
2558de0ae958SIsrael Rukshin 			 unsigned int *meta_sg_offset)
2559de0ae958SIsrael Rukshin {
2560de0ae958SIsrael Rukshin 	struct mlx5_ib_mr *mr = to_mmr(ibmr);
25612563e2f3SMax Gurtovoy 	struct mlx5_ib_mr *pi_mr = NULL;
2562de0ae958SIsrael Rukshin 	int n;
2563de0ae958SIsrael Rukshin 
2564de0ae958SIsrael Rukshin 	WARN_ON(ibmr->type != IB_MR_TYPE_INTEGRITY);
2565de0ae958SIsrael Rukshin 
2566ae0579acSAharon Landau 	mr->mmkey.ndescs = 0;
25672563e2f3SMax Gurtovoy 	mr->data_length = 0;
25682563e2f3SMax Gurtovoy 	mr->data_iova = 0;
25692563e2f3SMax Gurtovoy 	mr->meta_ndescs = 0;
25702563e2f3SMax Gurtovoy 	mr->pi_iova = 0;
25712563e2f3SMax Gurtovoy 	/*
25722563e2f3SMax Gurtovoy 	 * As a performance optimization, if possible, there is no need to
25732563e2f3SMax Gurtovoy 	 * perform UMR operation to register the data/metadata buffers.
25742563e2f3SMax Gurtovoy 	 * First try to map the sg lists to PA descriptors with local_dma_lkey.
25752563e2f3SMax Gurtovoy 	 * Fallback to UMR only in case of a failure.
25762563e2f3SMax Gurtovoy 	 */
25772563e2f3SMax Gurtovoy 	n = mlx5_ib_map_pa_mr_sg_pi(ibmr, data_sg, data_sg_nents,
25782563e2f3SMax Gurtovoy 				    data_sg_offset, meta_sg, meta_sg_nents,
25792563e2f3SMax Gurtovoy 				    meta_sg_offset);
25802563e2f3SMax Gurtovoy 	if (n == data_sg_nents + meta_sg_nents)
25812563e2f3SMax Gurtovoy 		goto out;
2582de0ae958SIsrael Rukshin 	/*
2583de0ae958SIsrael Rukshin 	 * As a performance optimization, if possible, there is no need to map
2584de0ae958SIsrael Rukshin 	 * the sg lists to KLM descriptors. First try to map the sg lists to MTT
2585de0ae958SIsrael Rukshin 	 * descriptors and fallback to KLM only in case of a failure.
2586de0ae958SIsrael Rukshin 	 * It's more efficient for the HW to work with MTT descriptors
2587de0ae958SIsrael Rukshin 	 * (especially in high load).
2588de0ae958SIsrael Rukshin 	 * Use KLM (indirect access) only if it's mandatory.
2589de0ae958SIsrael Rukshin 	 */
25902563e2f3SMax Gurtovoy 	pi_mr = mr->mtt_mr;
2591de0ae958SIsrael Rukshin 	n = mlx5_ib_map_mtt_mr_sg_pi(ibmr, data_sg, data_sg_nents,
2592de0ae958SIsrael Rukshin 				     data_sg_offset, meta_sg, meta_sg_nents,
2593de0ae958SIsrael Rukshin 				     meta_sg_offset);
2594de0ae958SIsrael Rukshin 	if (n == data_sg_nents + meta_sg_nents)
2595de0ae958SIsrael Rukshin 		goto out;
2596de0ae958SIsrael Rukshin 
2597de0ae958SIsrael Rukshin 	pi_mr = mr->klm_mr;
2598de0ae958SIsrael Rukshin 	n = mlx5_ib_map_klm_mr_sg_pi(ibmr, data_sg, data_sg_nents,
2599de0ae958SIsrael Rukshin 				     data_sg_offset, meta_sg, meta_sg_nents,
2600de0ae958SIsrael Rukshin 				     meta_sg_offset);
26016c984472SMax Gurtovoy 	if (unlikely(n != data_sg_nents + meta_sg_nents))
26026c984472SMax Gurtovoy 		return -ENOMEM;
26036c984472SMax Gurtovoy 
2604de0ae958SIsrael Rukshin out:
2605de0ae958SIsrael Rukshin 	/* This is zero-based memory region */
2606de0ae958SIsrael Rukshin 	ibmr->iova = 0;
2607de0ae958SIsrael Rukshin 	mr->pi_mr = pi_mr;
26082563e2f3SMax Gurtovoy 	if (pi_mr)
2609de0ae958SIsrael Rukshin 		ibmr->sig_attrs->meta_length = pi_mr->meta_length;
26102563e2f3SMax Gurtovoy 	else
26112563e2f3SMax Gurtovoy 		ibmr->sig_attrs->meta_length = mr->meta_length;
2612de0ae958SIsrael Rukshin 
26136c984472SMax Gurtovoy 	return 0;
26146c984472SMax Gurtovoy }
26156c984472SMax Gurtovoy 
mlx5_ib_map_mr_sg(struct ib_mr * ibmr,struct scatterlist * sg,int sg_nents,unsigned int * sg_offset)2616ff2ba993SChristoph Hellwig int mlx5_ib_map_mr_sg(struct ib_mr *ibmr, struct scatterlist *sg, int sg_nents,
26179aa8b321SBart Van Assche 		      unsigned int *sg_offset)
26188a187ee5SSagi Grimberg {
26198a187ee5SSagi Grimberg 	struct mlx5_ib_mr *mr = to_mmr(ibmr);
26208a187ee5SSagi Grimberg 	int n;
26218a187ee5SSagi Grimberg 
2622ae0579acSAharon Landau 	mr->mmkey.ndescs = 0;
26238a187ee5SSagi Grimberg 
26248a187ee5SSagi Grimberg 	ib_dma_sync_single_for_cpu(ibmr->device, mr->desc_map,
26258a187ee5SSagi Grimberg 				   mr->desc_size * mr->max_descs,
26268a187ee5SSagi Grimberg 				   DMA_TO_DEVICE);
26278a187ee5SSagi Grimberg 
2628ec22eb53SSaeed Mahameed 	if (mr->access_mode == MLX5_MKC_ACCESS_MODE_KLMS)
26296c984472SMax Gurtovoy 		n = mlx5_ib_sg_to_klms(mr, sg, sg_nents, sg_offset, NULL, 0,
26306c984472SMax Gurtovoy 				       NULL);
2631b005d316SSagi Grimberg 	else
2632ff2ba993SChristoph Hellwig 		n = ib_sg_to_pages(ibmr, sg, sg_nents, sg_offset,
2633ff2ba993SChristoph Hellwig 				mlx5_set_page);
26348a187ee5SSagi Grimberg 
26358a187ee5SSagi Grimberg 	ib_dma_sync_single_for_device(ibmr->device, mr->desc_map,
26368a187ee5SSagi Grimberg 				      mr->desc_size * mr->max_descs,
26378a187ee5SSagi Grimberg 				      DMA_TO_DEVICE);
26388a187ee5SSagi Grimberg 
26398a187ee5SSagi Grimberg 	return n;
26408a187ee5SSagi Grimberg }
2641