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