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