162306a36Sopenharmony_ci/*
262306a36Sopenharmony_ci * Copyright (c) 2016 Hisilicon Limited.
362306a36Sopenharmony_ci * Copyright (c) 2007, 2008 Mellanox Technologies. All rights reserved.
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * This software is available to you under a choice of one of two
662306a36Sopenharmony_ci * licenses.  You may choose to be licensed under the terms of the GNU
762306a36Sopenharmony_ci * General Public License (GPL) Version 2, available from the file
862306a36Sopenharmony_ci * COPYING in the main directory of this source tree, or the
962306a36Sopenharmony_ci * OpenIB.org BSD license below:
1062306a36Sopenharmony_ci *
1162306a36Sopenharmony_ci *     Redistribution and use in source and binary forms, with or
1262306a36Sopenharmony_ci *     without modification, are permitted provided that the following
1362306a36Sopenharmony_ci *     conditions are met:
1462306a36Sopenharmony_ci *
1562306a36Sopenharmony_ci *      - Redistributions of source code must retain the above
1662306a36Sopenharmony_ci *        copyright notice, this list of conditions and the following
1762306a36Sopenharmony_ci *        disclaimer.
1862306a36Sopenharmony_ci *
1962306a36Sopenharmony_ci *      - Redistributions in binary form must reproduce the above
2062306a36Sopenharmony_ci *        copyright notice, this list of conditions and the following
2162306a36Sopenharmony_ci *        disclaimer in the documentation and/or other materials
2262306a36Sopenharmony_ci *        provided with the distribution.
2362306a36Sopenharmony_ci *
2462306a36Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
2562306a36Sopenharmony_ci * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
2662306a36Sopenharmony_ci * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
2762306a36Sopenharmony_ci * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
2862306a36Sopenharmony_ci * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
2962306a36Sopenharmony_ci * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
3062306a36Sopenharmony_ci * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
3162306a36Sopenharmony_ci * SOFTWARE.
3262306a36Sopenharmony_ci */
3362306a36Sopenharmony_ci
3462306a36Sopenharmony_ci#include <linux/vmalloc.h>
3562306a36Sopenharmony_ci#include <rdma/ib_umem.h>
3662306a36Sopenharmony_ci#include <linux/math.h>
3762306a36Sopenharmony_ci#include "hns_roce_device.h"
3862306a36Sopenharmony_ci#include "hns_roce_cmd.h"
3962306a36Sopenharmony_ci#include "hns_roce_hem.h"
4062306a36Sopenharmony_ci
4162306a36Sopenharmony_cistatic u32 hw_index_to_key(int ind)
4262306a36Sopenharmony_ci{
4362306a36Sopenharmony_ci	return ((u32)ind >> 24) | ((u32)ind << 8);
4462306a36Sopenharmony_ci}
4562306a36Sopenharmony_ci
4662306a36Sopenharmony_ciunsigned long key_to_hw_index(u32 key)
4762306a36Sopenharmony_ci{
4862306a36Sopenharmony_ci	return (key << 24) | (key >> 8);
4962306a36Sopenharmony_ci}
5062306a36Sopenharmony_ci
5162306a36Sopenharmony_cistatic int alloc_mr_key(struct hns_roce_dev *hr_dev, struct hns_roce_mr *mr)
5262306a36Sopenharmony_ci{
5362306a36Sopenharmony_ci	struct hns_roce_ida *mtpt_ida = &hr_dev->mr_table.mtpt_ida;
5462306a36Sopenharmony_ci	struct ib_device *ibdev = &hr_dev->ib_dev;
5562306a36Sopenharmony_ci	int err;
5662306a36Sopenharmony_ci	int id;
5762306a36Sopenharmony_ci
5862306a36Sopenharmony_ci	/* Allocate a key for mr from mr_table */
5962306a36Sopenharmony_ci	id = ida_alloc_range(&mtpt_ida->ida, mtpt_ida->min, mtpt_ida->max,
6062306a36Sopenharmony_ci			     GFP_KERNEL);
6162306a36Sopenharmony_ci	if (id < 0) {
6262306a36Sopenharmony_ci		ibdev_err(ibdev, "failed to alloc id for MR key, id(%d)\n", id);
6362306a36Sopenharmony_ci		return -ENOMEM;
6462306a36Sopenharmony_ci	}
6562306a36Sopenharmony_ci
6662306a36Sopenharmony_ci	mr->key = hw_index_to_key(id); /* MR key */
6762306a36Sopenharmony_ci
6862306a36Sopenharmony_ci	err = hns_roce_table_get(hr_dev, &hr_dev->mr_table.mtpt_table,
6962306a36Sopenharmony_ci				 (unsigned long)id);
7062306a36Sopenharmony_ci	if (err) {
7162306a36Sopenharmony_ci		ibdev_err(ibdev, "failed to alloc mtpt, ret = %d.\n", err);
7262306a36Sopenharmony_ci		goto err_free_bitmap;
7362306a36Sopenharmony_ci	}
7462306a36Sopenharmony_ci
7562306a36Sopenharmony_ci	return 0;
7662306a36Sopenharmony_cierr_free_bitmap:
7762306a36Sopenharmony_ci	ida_free(&mtpt_ida->ida, id);
7862306a36Sopenharmony_ci	return err;
7962306a36Sopenharmony_ci}
8062306a36Sopenharmony_ci
8162306a36Sopenharmony_cistatic void free_mr_key(struct hns_roce_dev *hr_dev, struct hns_roce_mr *mr)
8262306a36Sopenharmony_ci{
8362306a36Sopenharmony_ci	unsigned long obj = key_to_hw_index(mr->key);
8462306a36Sopenharmony_ci
8562306a36Sopenharmony_ci	hns_roce_table_put(hr_dev, &hr_dev->mr_table.mtpt_table, obj);
8662306a36Sopenharmony_ci	ida_free(&hr_dev->mr_table.mtpt_ida.ida, (int)obj);
8762306a36Sopenharmony_ci}
8862306a36Sopenharmony_ci
8962306a36Sopenharmony_cistatic int alloc_mr_pbl(struct hns_roce_dev *hr_dev, struct hns_roce_mr *mr,
9062306a36Sopenharmony_ci			struct ib_udata *udata, u64 start)
9162306a36Sopenharmony_ci{
9262306a36Sopenharmony_ci	struct ib_device *ibdev = &hr_dev->ib_dev;
9362306a36Sopenharmony_ci	bool is_fast = mr->type == MR_TYPE_FRMR;
9462306a36Sopenharmony_ci	struct hns_roce_buf_attr buf_attr = {};
9562306a36Sopenharmony_ci	int err;
9662306a36Sopenharmony_ci
9762306a36Sopenharmony_ci	mr->pbl_hop_num = is_fast ? 1 : hr_dev->caps.pbl_hop_num;
9862306a36Sopenharmony_ci	buf_attr.page_shift = is_fast ? PAGE_SHIFT :
9962306a36Sopenharmony_ci			      hr_dev->caps.pbl_buf_pg_sz + PAGE_SHIFT;
10062306a36Sopenharmony_ci	buf_attr.region[0].size = mr->size;
10162306a36Sopenharmony_ci	buf_attr.region[0].hopnum = mr->pbl_hop_num;
10262306a36Sopenharmony_ci	buf_attr.region_count = 1;
10362306a36Sopenharmony_ci	buf_attr.user_access = mr->access;
10462306a36Sopenharmony_ci	/* fast MR's buffer is alloced before mapping, not at creation */
10562306a36Sopenharmony_ci	buf_attr.mtt_only = is_fast;
10662306a36Sopenharmony_ci
10762306a36Sopenharmony_ci	err = hns_roce_mtr_create(hr_dev, &mr->pbl_mtr, &buf_attr,
10862306a36Sopenharmony_ci				  hr_dev->caps.pbl_ba_pg_sz + PAGE_SHIFT,
10962306a36Sopenharmony_ci				  udata, start);
11062306a36Sopenharmony_ci	if (err)
11162306a36Sopenharmony_ci		ibdev_err(ibdev, "failed to alloc pbl mtr, ret = %d.\n", err);
11262306a36Sopenharmony_ci	else
11362306a36Sopenharmony_ci		mr->npages = mr->pbl_mtr.hem_cfg.buf_pg_count;
11462306a36Sopenharmony_ci
11562306a36Sopenharmony_ci	return err;
11662306a36Sopenharmony_ci}
11762306a36Sopenharmony_ci
11862306a36Sopenharmony_cistatic void free_mr_pbl(struct hns_roce_dev *hr_dev, struct hns_roce_mr *mr)
11962306a36Sopenharmony_ci{
12062306a36Sopenharmony_ci	hns_roce_mtr_destroy(hr_dev, &mr->pbl_mtr);
12162306a36Sopenharmony_ci}
12262306a36Sopenharmony_ci
12362306a36Sopenharmony_cistatic void hns_roce_mr_free(struct hns_roce_dev *hr_dev, struct hns_roce_mr *mr)
12462306a36Sopenharmony_ci{
12562306a36Sopenharmony_ci	struct ib_device *ibdev = &hr_dev->ib_dev;
12662306a36Sopenharmony_ci	int ret;
12762306a36Sopenharmony_ci
12862306a36Sopenharmony_ci	if (mr->enabled) {
12962306a36Sopenharmony_ci		ret = hns_roce_destroy_hw_ctx(hr_dev, HNS_ROCE_CMD_DESTROY_MPT,
13062306a36Sopenharmony_ci					      key_to_hw_index(mr->key) &
13162306a36Sopenharmony_ci					      (hr_dev->caps.num_mtpts - 1));
13262306a36Sopenharmony_ci		if (ret)
13362306a36Sopenharmony_ci			ibdev_warn(ibdev, "failed to destroy mpt, ret = %d.\n",
13462306a36Sopenharmony_ci				   ret);
13562306a36Sopenharmony_ci	}
13662306a36Sopenharmony_ci
13762306a36Sopenharmony_ci	free_mr_pbl(hr_dev, mr);
13862306a36Sopenharmony_ci	free_mr_key(hr_dev, mr);
13962306a36Sopenharmony_ci}
14062306a36Sopenharmony_ci
14162306a36Sopenharmony_cistatic int hns_roce_mr_enable(struct hns_roce_dev *hr_dev,
14262306a36Sopenharmony_ci			      struct hns_roce_mr *mr)
14362306a36Sopenharmony_ci{
14462306a36Sopenharmony_ci	unsigned long mtpt_idx = key_to_hw_index(mr->key);
14562306a36Sopenharmony_ci	struct hns_roce_cmd_mailbox *mailbox;
14662306a36Sopenharmony_ci	struct device *dev = hr_dev->dev;
14762306a36Sopenharmony_ci	int ret;
14862306a36Sopenharmony_ci
14962306a36Sopenharmony_ci	/* Allocate mailbox memory */
15062306a36Sopenharmony_ci	mailbox = hns_roce_alloc_cmd_mailbox(hr_dev);
15162306a36Sopenharmony_ci	if (IS_ERR(mailbox))
15262306a36Sopenharmony_ci		return PTR_ERR(mailbox);
15362306a36Sopenharmony_ci
15462306a36Sopenharmony_ci	if (mr->type != MR_TYPE_FRMR)
15562306a36Sopenharmony_ci		ret = hr_dev->hw->write_mtpt(hr_dev, mailbox->buf, mr);
15662306a36Sopenharmony_ci	else
15762306a36Sopenharmony_ci		ret = hr_dev->hw->frmr_write_mtpt(hr_dev, mailbox->buf, mr);
15862306a36Sopenharmony_ci	if (ret) {
15962306a36Sopenharmony_ci		dev_err(dev, "failed to write mtpt, ret = %d.\n", ret);
16062306a36Sopenharmony_ci		goto err_page;
16162306a36Sopenharmony_ci	}
16262306a36Sopenharmony_ci
16362306a36Sopenharmony_ci	ret = hns_roce_create_hw_ctx(hr_dev, mailbox, HNS_ROCE_CMD_CREATE_MPT,
16462306a36Sopenharmony_ci				     mtpt_idx & (hr_dev->caps.num_mtpts - 1));
16562306a36Sopenharmony_ci	if (ret) {
16662306a36Sopenharmony_ci		dev_err(dev, "failed to create mpt, ret = %d.\n", ret);
16762306a36Sopenharmony_ci		goto err_page;
16862306a36Sopenharmony_ci	}
16962306a36Sopenharmony_ci
17062306a36Sopenharmony_ci	mr->enabled = 1;
17162306a36Sopenharmony_ci
17262306a36Sopenharmony_cierr_page:
17362306a36Sopenharmony_ci	hns_roce_free_cmd_mailbox(hr_dev, mailbox);
17462306a36Sopenharmony_ci
17562306a36Sopenharmony_ci	return ret;
17662306a36Sopenharmony_ci}
17762306a36Sopenharmony_ci
17862306a36Sopenharmony_civoid hns_roce_init_mr_table(struct hns_roce_dev *hr_dev)
17962306a36Sopenharmony_ci{
18062306a36Sopenharmony_ci	struct hns_roce_ida *mtpt_ida = &hr_dev->mr_table.mtpt_ida;
18162306a36Sopenharmony_ci
18262306a36Sopenharmony_ci	ida_init(&mtpt_ida->ida);
18362306a36Sopenharmony_ci	mtpt_ida->max = hr_dev->caps.num_mtpts - 1;
18462306a36Sopenharmony_ci	mtpt_ida->min = hr_dev->caps.reserved_mrws;
18562306a36Sopenharmony_ci}
18662306a36Sopenharmony_ci
18762306a36Sopenharmony_cistruct ib_mr *hns_roce_get_dma_mr(struct ib_pd *pd, int acc)
18862306a36Sopenharmony_ci{
18962306a36Sopenharmony_ci	struct hns_roce_dev *hr_dev = to_hr_dev(pd->device);
19062306a36Sopenharmony_ci	struct hns_roce_mr *mr;
19162306a36Sopenharmony_ci	int ret;
19262306a36Sopenharmony_ci
19362306a36Sopenharmony_ci	mr = kzalloc(sizeof(*mr), GFP_KERNEL);
19462306a36Sopenharmony_ci	if (!mr)
19562306a36Sopenharmony_ci		return  ERR_PTR(-ENOMEM);
19662306a36Sopenharmony_ci
19762306a36Sopenharmony_ci	mr->type = MR_TYPE_DMA;
19862306a36Sopenharmony_ci	mr->pd = to_hr_pd(pd)->pdn;
19962306a36Sopenharmony_ci	mr->access = acc;
20062306a36Sopenharmony_ci
20162306a36Sopenharmony_ci	/* Allocate memory region key */
20262306a36Sopenharmony_ci	hns_roce_hem_list_init(&mr->pbl_mtr.hem_list);
20362306a36Sopenharmony_ci	ret = alloc_mr_key(hr_dev, mr);
20462306a36Sopenharmony_ci	if (ret)
20562306a36Sopenharmony_ci		goto err_free;
20662306a36Sopenharmony_ci
20762306a36Sopenharmony_ci	ret = hns_roce_mr_enable(hr_dev, mr);
20862306a36Sopenharmony_ci	if (ret)
20962306a36Sopenharmony_ci		goto err_mr;
21062306a36Sopenharmony_ci
21162306a36Sopenharmony_ci	mr->ibmr.rkey = mr->ibmr.lkey = mr->key;
21262306a36Sopenharmony_ci
21362306a36Sopenharmony_ci	return &mr->ibmr;
21462306a36Sopenharmony_cierr_mr:
21562306a36Sopenharmony_ci	free_mr_key(hr_dev, mr);
21662306a36Sopenharmony_ci
21762306a36Sopenharmony_cierr_free:
21862306a36Sopenharmony_ci	kfree(mr);
21962306a36Sopenharmony_ci	return ERR_PTR(ret);
22062306a36Sopenharmony_ci}
22162306a36Sopenharmony_ci
22262306a36Sopenharmony_cistruct ib_mr *hns_roce_reg_user_mr(struct ib_pd *pd, u64 start, u64 length,
22362306a36Sopenharmony_ci				   u64 virt_addr, int access_flags,
22462306a36Sopenharmony_ci				   struct ib_udata *udata)
22562306a36Sopenharmony_ci{
22662306a36Sopenharmony_ci	struct hns_roce_dev *hr_dev = to_hr_dev(pd->device);
22762306a36Sopenharmony_ci	struct hns_roce_mr *mr;
22862306a36Sopenharmony_ci	int ret;
22962306a36Sopenharmony_ci
23062306a36Sopenharmony_ci	mr = kzalloc(sizeof(*mr), GFP_KERNEL);
23162306a36Sopenharmony_ci	if (!mr)
23262306a36Sopenharmony_ci		return ERR_PTR(-ENOMEM);
23362306a36Sopenharmony_ci
23462306a36Sopenharmony_ci	mr->iova = virt_addr;
23562306a36Sopenharmony_ci	mr->size = length;
23662306a36Sopenharmony_ci	mr->pd = to_hr_pd(pd)->pdn;
23762306a36Sopenharmony_ci	mr->access = access_flags;
23862306a36Sopenharmony_ci	mr->type = MR_TYPE_MR;
23962306a36Sopenharmony_ci
24062306a36Sopenharmony_ci	ret = alloc_mr_key(hr_dev, mr);
24162306a36Sopenharmony_ci	if (ret)
24262306a36Sopenharmony_ci		goto err_alloc_mr;
24362306a36Sopenharmony_ci
24462306a36Sopenharmony_ci	ret = alloc_mr_pbl(hr_dev, mr, udata, start);
24562306a36Sopenharmony_ci	if (ret)
24662306a36Sopenharmony_ci		goto err_alloc_key;
24762306a36Sopenharmony_ci
24862306a36Sopenharmony_ci	ret = hns_roce_mr_enable(hr_dev, mr);
24962306a36Sopenharmony_ci	if (ret)
25062306a36Sopenharmony_ci		goto err_alloc_pbl;
25162306a36Sopenharmony_ci
25262306a36Sopenharmony_ci	mr->ibmr.rkey = mr->ibmr.lkey = mr->key;
25362306a36Sopenharmony_ci
25462306a36Sopenharmony_ci	return &mr->ibmr;
25562306a36Sopenharmony_ci
25662306a36Sopenharmony_cierr_alloc_pbl:
25762306a36Sopenharmony_ci	free_mr_pbl(hr_dev, mr);
25862306a36Sopenharmony_cierr_alloc_key:
25962306a36Sopenharmony_ci	free_mr_key(hr_dev, mr);
26062306a36Sopenharmony_cierr_alloc_mr:
26162306a36Sopenharmony_ci	kfree(mr);
26262306a36Sopenharmony_ci	return ERR_PTR(ret);
26362306a36Sopenharmony_ci}
26462306a36Sopenharmony_ci
26562306a36Sopenharmony_cistruct ib_mr *hns_roce_rereg_user_mr(struct ib_mr *ibmr, int flags, u64 start,
26662306a36Sopenharmony_ci				     u64 length, u64 virt_addr,
26762306a36Sopenharmony_ci				     int mr_access_flags, struct ib_pd *pd,
26862306a36Sopenharmony_ci				     struct ib_udata *udata)
26962306a36Sopenharmony_ci{
27062306a36Sopenharmony_ci	struct hns_roce_dev *hr_dev = to_hr_dev(ibmr->device);
27162306a36Sopenharmony_ci	struct ib_device *ib_dev = &hr_dev->ib_dev;
27262306a36Sopenharmony_ci	struct hns_roce_mr *mr = to_hr_mr(ibmr);
27362306a36Sopenharmony_ci	struct hns_roce_cmd_mailbox *mailbox;
27462306a36Sopenharmony_ci	unsigned long mtpt_idx;
27562306a36Sopenharmony_ci	int ret;
27662306a36Sopenharmony_ci
27762306a36Sopenharmony_ci	if (!mr->enabled)
27862306a36Sopenharmony_ci		return ERR_PTR(-EINVAL);
27962306a36Sopenharmony_ci
28062306a36Sopenharmony_ci	mailbox = hns_roce_alloc_cmd_mailbox(hr_dev);
28162306a36Sopenharmony_ci	if (IS_ERR(mailbox))
28262306a36Sopenharmony_ci		return ERR_CAST(mailbox);
28362306a36Sopenharmony_ci
28462306a36Sopenharmony_ci	mtpt_idx = key_to_hw_index(mr->key) & (hr_dev->caps.num_mtpts - 1);
28562306a36Sopenharmony_ci
28662306a36Sopenharmony_ci	ret = hns_roce_cmd_mbox(hr_dev, 0, mailbox->dma, HNS_ROCE_CMD_QUERY_MPT,
28762306a36Sopenharmony_ci				mtpt_idx);
28862306a36Sopenharmony_ci	if (ret)
28962306a36Sopenharmony_ci		goto free_cmd_mbox;
29062306a36Sopenharmony_ci
29162306a36Sopenharmony_ci	ret = hns_roce_destroy_hw_ctx(hr_dev, HNS_ROCE_CMD_DESTROY_MPT,
29262306a36Sopenharmony_ci				      mtpt_idx);
29362306a36Sopenharmony_ci	if (ret)
29462306a36Sopenharmony_ci		ibdev_warn(ib_dev, "failed to destroy MPT, ret = %d.\n", ret);
29562306a36Sopenharmony_ci
29662306a36Sopenharmony_ci	mr->enabled = 0;
29762306a36Sopenharmony_ci	mr->iova = virt_addr;
29862306a36Sopenharmony_ci	mr->size = length;
29962306a36Sopenharmony_ci
30062306a36Sopenharmony_ci	if (flags & IB_MR_REREG_PD)
30162306a36Sopenharmony_ci		mr->pd = to_hr_pd(pd)->pdn;
30262306a36Sopenharmony_ci
30362306a36Sopenharmony_ci	if (flags & IB_MR_REREG_ACCESS)
30462306a36Sopenharmony_ci		mr->access = mr_access_flags;
30562306a36Sopenharmony_ci
30662306a36Sopenharmony_ci	if (flags & IB_MR_REREG_TRANS) {
30762306a36Sopenharmony_ci		free_mr_pbl(hr_dev, mr);
30862306a36Sopenharmony_ci		ret = alloc_mr_pbl(hr_dev, mr, udata, start);
30962306a36Sopenharmony_ci		if (ret) {
31062306a36Sopenharmony_ci			ibdev_err(ib_dev, "failed to alloc mr PBL, ret = %d.\n",
31162306a36Sopenharmony_ci				  ret);
31262306a36Sopenharmony_ci			goto free_cmd_mbox;
31362306a36Sopenharmony_ci		}
31462306a36Sopenharmony_ci	}
31562306a36Sopenharmony_ci
31662306a36Sopenharmony_ci	ret = hr_dev->hw->rereg_write_mtpt(hr_dev, mr, flags, mailbox->buf);
31762306a36Sopenharmony_ci	if (ret) {
31862306a36Sopenharmony_ci		ibdev_err(ib_dev, "failed to write mtpt, ret = %d.\n", ret);
31962306a36Sopenharmony_ci		goto free_cmd_mbox;
32062306a36Sopenharmony_ci	}
32162306a36Sopenharmony_ci
32262306a36Sopenharmony_ci	ret = hns_roce_create_hw_ctx(hr_dev, mailbox, HNS_ROCE_CMD_CREATE_MPT,
32362306a36Sopenharmony_ci				     mtpt_idx);
32462306a36Sopenharmony_ci	if (ret) {
32562306a36Sopenharmony_ci		ibdev_err(ib_dev, "failed to create MPT, ret = %d.\n", ret);
32662306a36Sopenharmony_ci		goto free_cmd_mbox;
32762306a36Sopenharmony_ci	}
32862306a36Sopenharmony_ci
32962306a36Sopenharmony_ci	mr->enabled = 1;
33062306a36Sopenharmony_ci
33162306a36Sopenharmony_cifree_cmd_mbox:
33262306a36Sopenharmony_ci	hns_roce_free_cmd_mailbox(hr_dev, mailbox);
33362306a36Sopenharmony_ci
33462306a36Sopenharmony_ci	if (ret)
33562306a36Sopenharmony_ci		return ERR_PTR(ret);
33662306a36Sopenharmony_ci	return NULL;
33762306a36Sopenharmony_ci}
33862306a36Sopenharmony_ci
33962306a36Sopenharmony_ciint hns_roce_dereg_mr(struct ib_mr *ibmr, struct ib_udata *udata)
34062306a36Sopenharmony_ci{
34162306a36Sopenharmony_ci	struct hns_roce_dev *hr_dev = to_hr_dev(ibmr->device);
34262306a36Sopenharmony_ci	struct hns_roce_mr *mr = to_hr_mr(ibmr);
34362306a36Sopenharmony_ci
34462306a36Sopenharmony_ci	if (hr_dev->hw->dereg_mr)
34562306a36Sopenharmony_ci		hr_dev->hw->dereg_mr(hr_dev);
34662306a36Sopenharmony_ci
34762306a36Sopenharmony_ci	hns_roce_mr_free(hr_dev, mr);
34862306a36Sopenharmony_ci	kfree(mr);
34962306a36Sopenharmony_ci
35062306a36Sopenharmony_ci	return 0;
35162306a36Sopenharmony_ci}
35262306a36Sopenharmony_ci
35362306a36Sopenharmony_cistruct ib_mr *hns_roce_alloc_mr(struct ib_pd *pd, enum ib_mr_type mr_type,
35462306a36Sopenharmony_ci				u32 max_num_sg)
35562306a36Sopenharmony_ci{
35662306a36Sopenharmony_ci	struct hns_roce_dev *hr_dev = to_hr_dev(pd->device);
35762306a36Sopenharmony_ci	struct device *dev = hr_dev->dev;
35862306a36Sopenharmony_ci	struct hns_roce_mr *mr;
35962306a36Sopenharmony_ci	int ret;
36062306a36Sopenharmony_ci
36162306a36Sopenharmony_ci	if (mr_type != IB_MR_TYPE_MEM_REG)
36262306a36Sopenharmony_ci		return ERR_PTR(-EINVAL);
36362306a36Sopenharmony_ci
36462306a36Sopenharmony_ci	if (max_num_sg > HNS_ROCE_FRMR_MAX_PA) {
36562306a36Sopenharmony_ci		dev_err(dev, "max_num_sg larger than %d\n",
36662306a36Sopenharmony_ci			HNS_ROCE_FRMR_MAX_PA);
36762306a36Sopenharmony_ci		return ERR_PTR(-EINVAL);
36862306a36Sopenharmony_ci	}
36962306a36Sopenharmony_ci
37062306a36Sopenharmony_ci	mr = kzalloc(sizeof(*mr), GFP_KERNEL);
37162306a36Sopenharmony_ci	if (!mr)
37262306a36Sopenharmony_ci		return ERR_PTR(-ENOMEM);
37362306a36Sopenharmony_ci
37462306a36Sopenharmony_ci	mr->type = MR_TYPE_FRMR;
37562306a36Sopenharmony_ci	mr->pd = to_hr_pd(pd)->pdn;
37662306a36Sopenharmony_ci	mr->size = max_num_sg * (1 << PAGE_SHIFT);
37762306a36Sopenharmony_ci
37862306a36Sopenharmony_ci	/* Allocate memory region key */
37962306a36Sopenharmony_ci	ret = alloc_mr_key(hr_dev, mr);
38062306a36Sopenharmony_ci	if (ret)
38162306a36Sopenharmony_ci		goto err_free;
38262306a36Sopenharmony_ci
38362306a36Sopenharmony_ci	ret = alloc_mr_pbl(hr_dev, mr, NULL, 0);
38462306a36Sopenharmony_ci	if (ret)
38562306a36Sopenharmony_ci		goto err_key;
38662306a36Sopenharmony_ci
38762306a36Sopenharmony_ci	ret = hns_roce_mr_enable(hr_dev, mr);
38862306a36Sopenharmony_ci	if (ret)
38962306a36Sopenharmony_ci		goto err_pbl;
39062306a36Sopenharmony_ci
39162306a36Sopenharmony_ci	mr->ibmr.rkey = mr->ibmr.lkey = mr->key;
39262306a36Sopenharmony_ci	mr->ibmr.length = mr->size;
39362306a36Sopenharmony_ci
39462306a36Sopenharmony_ci	return &mr->ibmr;
39562306a36Sopenharmony_ci
39662306a36Sopenharmony_cierr_pbl:
39762306a36Sopenharmony_ci	free_mr_pbl(hr_dev, mr);
39862306a36Sopenharmony_cierr_key:
39962306a36Sopenharmony_ci	free_mr_key(hr_dev, mr);
40062306a36Sopenharmony_cierr_free:
40162306a36Sopenharmony_ci	kfree(mr);
40262306a36Sopenharmony_ci	return ERR_PTR(ret);
40362306a36Sopenharmony_ci}
40462306a36Sopenharmony_ci
40562306a36Sopenharmony_cistatic int hns_roce_set_page(struct ib_mr *ibmr, u64 addr)
40662306a36Sopenharmony_ci{
40762306a36Sopenharmony_ci	struct hns_roce_mr *mr = to_hr_mr(ibmr);
40862306a36Sopenharmony_ci
40962306a36Sopenharmony_ci	if (likely(mr->npages < mr->pbl_mtr.hem_cfg.buf_pg_count)) {
41062306a36Sopenharmony_ci		mr->page_list[mr->npages++] = addr;
41162306a36Sopenharmony_ci		return 0;
41262306a36Sopenharmony_ci	}
41362306a36Sopenharmony_ci
41462306a36Sopenharmony_ci	return -ENOBUFS;
41562306a36Sopenharmony_ci}
41662306a36Sopenharmony_ci
41762306a36Sopenharmony_ciint hns_roce_map_mr_sg(struct ib_mr *ibmr, struct scatterlist *sg, int sg_nents,
41862306a36Sopenharmony_ci		       unsigned int *sg_offset)
41962306a36Sopenharmony_ci{
42062306a36Sopenharmony_ci	struct hns_roce_dev *hr_dev = to_hr_dev(ibmr->device);
42162306a36Sopenharmony_ci	struct ib_device *ibdev = &hr_dev->ib_dev;
42262306a36Sopenharmony_ci	struct hns_roce_mr *mr = to_hr_mr(ibmr);
42362306a36Sopenharmony_ci	struct hns_roce_mtr *mtr = &mr->pbl_mtr;
42462306a36Sopenharmony_ci	int ret = 0;
42562306a36Sopenharmony_ci
42662306a36Sopenharmony_ci	mr->npages = 0;
42762306a36Sopenharmony_ci	mr->page_list = kvcalloc(mr->pbl_mtr.hem_cfg.buf_pg_count,
42862306a36Sopenharmony_ci				 sizeof(dma_addr_t), GFP_KERNEL);
42962306a36Sopenharmony_ci	if (!mr->page_list)
43062306a36Sopenharmony_ci		return ret;
43162306a36Sopenharmony_ci
43262306a36Sopenharmony_ci	ret = ib_sg_to_pages(ibmr, sg, sg_nents, sg_offset, hns_roce_set_page);
43362306a36Sopenharmony_ci	if (ret < 1) {
43462306a36Sopenharmony_ci		ibdev_err(ibdev, "failed to store sg pages %u %u, cnt = %d.\n",
43562306a36Sopenharmony_ci			  mr->npages, mr->pbl_mtr.hem_cfg.buf_pg_count, ret);
43662306a36Sopenharmony_ci		goto err_page_list;
43762306a36Sopenharmony_ci	}
43862306a36Sopenharmony_ci
43962306a36Sopenharmony_ci	mtr->hem_cfg.region[0].offset = 0;
44062306a36Sopenharmony_ci	mtr->hem_cfg.region[0].count = mr->npages;
44162306a36Sopenharmony_ci	mtr->hem_cfg.region[0].hopnum = mr->pbl_hop_num;
44262306a36Sopenharmony_ci	mtr->hem_cfg.region_count = 1;
44362306a36Sopenharmony_ci	ret = hns_roce_mtr_map(hr_dev, mtr, mr->page_list, mr->npages);
44462306a36Sopenharmony_ci	if (ret) {
44562306a36Sopenharmony_ci		ibdev_err(ibdev, "failed to map sg mtr, ret = %d.\n", ret);
44662306a36Sopenharmony_ci		ret = 0;
44762306a36Sopenharmony_ci	} else {
44862306a36Sopenharmony_ci		mr->pbl_mtr.hem_cfg.buf_pg_shift = (u32)ilog2(ibmr->page_size);
44962306a36Sopenharmony_ci		ret = mr->npages;
45062306a36Sopenharmony_ci	}
45162306a36Sopenharmony_ci
45262306a36Sopenharmony_cierr_page_list:
45362306a36Sopenharmony_ci	kvfree(mr->page_list);
45462306a36Sopenharmony_ci	mr->page_list = NULL;
45562306a36Sopenharmony_ci
45662306a36Sopenharmony_ci	return ret;
45762306a36Sopenharmony_ci}
45862306a36Sopenharmony_ci
45962306a36Sopenharmony_cistatic void hns_roce_mw_free(struct hns_roce_dev *hr_dev,
46062306a36Sopenharmony_ci			     struct hns_roce_mw *mw)
46162306a36Sopenharmony_ci{
46262306a36Sopenharmony_ci	struct device *dev = hr_dev->dev;
46362306a36Sopenharmony_ci	int ret;
46462306a36Sopenharmony_ci
46562306a36Sopenharmony_ci	if (mw->enabled) {
46662306a36Sopenharmony_ci		ret = hns_roce_destroy_hw_ctx(hr_dev, HNS_ROCE_CMD_DESTROY_MPT,
46762306a36Sopenharmony_ci					      key_to_hw_index(mw->rkey) &
46862306a36Sopenharmony_ci					      (hr_dev->caps.num_mtpts - 1));
46962306a36Sopenharmony_ci		if (ret)
47062306a36Sopenharmony_ci			dev_warn(dev, "MW DESTROY_MPT failed (%d)\n", ret);
47162306a36Sopenharmony_ci
47262306a36Sopenharmony_ci		hns_roce_table_put(hr_dev, &hr_dev->mr_table.mtpt_table,
47362306a36Sopenharmony_ci				   key_to_hw_index(mw->rkey));
47462306a36Sopenharmony_ci	}
47562306a36Sopenharmony_ci
47662306a36Sopenharmony_ci	ida_free(&hr_dev->mr_table.mtpt_ida.ida,
47762306a36Sopenharmony_ci		 (int)key_to_hw_index(mw->rkey));
47862306a36Sopenharmony_ci}
47962306a36Sopenharmony_ci
48062306a36Sopenharmony_cistatic int hns_roce_mw_enable(struct hns_roce_dev *hr_dev,
48162306a36Sopenharmony_ci			      struct hns_roce_mw *mw)
48262306a36Sopenharmony_ci{
48362306a36Sopenharmony_ci	struct hns_roce_mr_table *mr_table = &hr_dev->mr_table;
48462306a36Sopenharmony_ci	struct hns_roce_cmd_mailbox *mailbox;
48562306a36Sopenharmony_ci	struct device *dev = hr_dev->dev;
48662306a36Sopenharmony_ci	unsigned long mtpt_idx = key_to_hw_index(mw->rkey);
48762306a36Sopenharmony_ci	int ret;
48862306a36Sopenharmony_ci
48962306a36Sopenharmony_ci	/* prepare HEM entry memory */
49062306a36Sopenharmony_ci	ret = hns_roce_table_get(hr_dev, &mr_table->mtpt_table, mtpt_idx);
49162306a36Sopenharmony_ci	if (ret)
49262306a36Sopenharmony_ci		return ret;
49362306a36Sopenharmony_ci
49462306a36Sopenharmony_ci	mailbox = hns_roce_alloc_cmd_mailbox(hr_dev);
49562306a36Sopenharmony_ci	if (IS_ERR(mailbox)) {
49662306a36Sopenharmony_ci		ret = PTR_ERR(mailbox);
49762306a36Sopenharmony_ci		goto err_table;
49862306a36Sopenharmony_ci	}
49962306a36Sopenharmony_ci
50062306a36Sopenharmony_ci	ret = hr_dev->hw->mw_write_mtpt(mailbox->buf, mw);
50162306a36Sopenharmony_ci	if (ret) {
50262306a36Sopenharmony_ci		dev_err(dev, "MW write mtpt fail!\n");
50362306a36Sopenharmony_ci		goto err_page;
50462306a36Sopenharmony_ci	}
50562306a36Sopenharmony_ci
50662306a36Sopenharmony_ci	ret = hns_roce_create_hw_ctx(hr_dev, mailbox, HNS_ROCE_CMD_CREATE_MPT,
50762306a36Sopenharmony_ci				     mtpt_idx & (hr_dev->caps.num_mtpts - 1));
50862306a36Sopenharmony_ci	if (ret) {
50962306a36Sopenharmony_ci		dev_err(dev, "MW CREATE_MPT failed (%d)\n", ret);
51062306a36Sopenharmony_ci		goto err_page;
51162306a36Sopenharmony_ci	}
51262306a36Sopenharmony_ci
51362306a36Sopenharmony_ci	mw->enabled = 1;
51462306a36Sopenharmony_ci
51562306a36Sopenharmony_ci	hns_roce_free_cmd_mailbox(hr_dev, mailbox);
51662306a36Sopenharmony_ci
51762306a36Sopenharmony_ci	return 0;
51862306a36Sopenharmony_ci
51962306a36Sopenharmony_cierr_page:
52062306a36Sopenharmony_ci	hns_roce_free_cmd_mailbox(hr_dev, mailbox);
52162306a36Sopenharmony_ci
52262306a36Sopenharmony_cierr_table:
52362306a36Sopenharmony_ci	hns_roce_table_put(hr_dev, &mr_table->mtpt_table, mtpt_idx);
52462306a36Sopenharmony_ci
52562306a36Sopenharmony_ci	return ret;
52662306a36Sopenharmony_ci}
52762306a36Sopenharmony_ci
52862306a36Sopenharmony_ciint hns_roce_alloc_mw(struct ib_mw *ibmw, struct ib_udata *udata)
52962306a36Sopenharmony_ci{
53062306a36Sopenharmony_ci	struct hns_roce_dev *hr_dev = to_hr_dev(ibmw->device);
53162306a36Sopenharmony_ci	struct hns_roce_ida *mtpt_ida = &hr_dev->mr_table.mtpt_ida;
53262306a36Sopenharmony_ci	struct ib_device *ibdev = &hr_dev->ib_dev;
53362306a36Sopenharmony_ci	struct hns_roce_mw *mw = to_hr_mw(ibmw);
53462306a36Sopenharmony_ci	int ret;
53562306a36Sopenharmony_ci	int id;
53662306a36Sopenharmony_ci
53762306a36Sopenharmony_ci	/* Allocate a key for mw from mr_table */
53862306a36Sopenharmony_ci	id = ida_alloc_range(&mtpt_ida->ida, mtpt_ida->min, mtpt_ida->max,
53962306a36Sopenharmony_ci			     GFP_KERNEL);
54062306a36Sopenharmony_ci	if (id < 0) {
54162306a36Sopenharmony_ci		ibdev_err(ibdev, "failed to alloc id for MW key, id(%d)\n", id);
54262306a36Sopenharmony_ci		return -ENOMEM;
54362306a36Sopenharmony_ci	}
54462306a36Sopenharmony_ci
54562306a36Sopenharmony_ci	mw->rkey = hw_index_to_key(id);
54662306a36Sopenharmony_ci
54762306a36Sopenharmony_ci	ibmw->rkey = mw->rkey;
54862306a36Sopenharmony_ci	mw->pdn = to_hr_pd(ibmw->pd)->pdn;
54962306a36Sopenharmony_ci	mw->pbl_hop_num = hr_dev->caps.pbl_hop_num;
55062306a36Sopenharmony_ci	mw->pbl_ba_pg_sz = hr_dev->caps.pbl_ba_pg_sz;
55162306a36Sopenharmony_ci	mw->pbl_buf_pg_sz = hr_dev->caps.pbl_buf_pg_sz;
55262306a36Sopenharmony_ci
55362306a36Sopenharmony_ci	ret = hns_roce_mw_enable(hr_dev, mw);
55462306a36Sopenharmony_ci	if (ret)
55562306a36Sopenharmony_ci		goto err_mw;
55662306a36Sopenharmony_ci
55762306a36Sopenharmony_ci	return 0;
55862306a36Sopenharmony_ci
55962306a36Sopenharmony_cierr_mw:
56062306a36Sopenharmony_ci	hns_roce_mw_free(hr_dev, mw);
56162306a36Sopenharmony_ci	return ret;
56262306a36Sopenharmony_ci}
56362306a36Sopenharmony_ci
56462306a36Sopenharmony_ciint hns_roce_dealloc_mw(struct ib_mw *ibmw)
56562306a36Sopenharmony_ci{
56662306a36Sopenharmony_ci	struct hns_roce_dev *hr_dev = to_hr_dev(ibmw->device);
56762306a36Sopenharmony_ci	struct hns_roce_mw *mw = to_hr_mw(ibmw);
56862306a36Sopenharmony_ci
56962306a36Sopenharmony_ci	hns_roce_mw_free(hr_dev, mw);
57062306a36Sopenharmony_ci	return 0;
57162306a36Sopenharmony_ci}
57262306a36Sopenharmony_ci
57362306a36Sopenharmony_cistatic int mtr_map_region(struct hns_roce_dev *hr_dev, struct hns_roce_mtr *mtr,
57462306a36Sopenharmony_ci			  struct hns_roce_buf_region *region, dma_addr_t *pages,
57562306a36Sopenharmony_ci			  int max_count)
57662306a36Sopenharmony_ci{
57762306a36Sopenharmony_ci	int count, npage;
57862306a36Sopenharmony_ci	int offset, end;
57962306a36Sopenharmony_ci	__le64 *mtts;
58062306a36Sopenharmony_ci	u64 addr;
58162306a36Sopenharmony_ci	int i;
58262306a36Sopenharmony_ci
58362306a36Sopenharmony_ci	offset = region->offset;
58462306a36Sopenharmony_ci	end = offset + region->count;
58562306a36Sopenharmony_ci	npage = 0;
58662306a36Sopenharmony_ci	while (offset < end && npage < max_count) {
58762306a36Sopenharmony_ci		count = 0;
58862306a36Sopenharmony_ci		mtts = hns_roce_hem_list_find_mtt(hr_dev, &mtr->hem_list,
58962306a36Sopenharmony_ci						  offset, &count);
59062306a36Sopenharmony_ci		if (!mtts)
59162306a36Sopenharmony_ci			return -ENOBUFS;
59262306a36Sopenharmony_ci
59362306a36Sopenharmony_ci		for (i = 0; i < count && npage < max_count; i++) {
59462306a36Sopenharmony_ci			addr = pages[npage];
59562306a36Sopenharmony_ci
59662306a36Sopenharmony_ci			mtts[i] = cpu_to_le64(addr);
59762306a36Sopenharmony_ci			npage++;
59862306a36Sopenharmony_ci		}
59962306a36Sopenharmony_ci		offset += count;
60062306a36Sopenharmony_ci	}
60162306a36Sopenharmony_ci
60262306a36Sopenharmony_ci	return npage;
60362306a36Sopenharmony_ci}
60462306a36Sopenharmony_ci
60562306a36Sopenharmony_cistatic inline bool mtr_has_mtt(struct hns_roce_buf_attr *attr)
60662306a36Sopenharmony_ci{
60762306a36Sopenharmony_ci	int i;
60862306a36Sopenharmony_ci
60962306a36Sopenharmony_ci	for (i = 0; i < attr->region_count; i++)
61062306a36Sopenharmony_ci		if (attr->region[i].hopnum != HNS_ROCE_HOP_NUM_0 &&
61162306a36Sopenharmony_ci		    attr->region[i].hopnum > 0)
61262306a36Sopenharmony_ci			return true;
61362306a36Sopenharmony_ci
61462306a36Sopenharmony_ci	/* because the mtr only one root base address, when hopnum is 0 means
61562306a36Sopenharmony_ci	 * root base address equals the first buffer address, thus all alloced
61662306a36Sopenharmony_ci	 * memory must in a continuous space accessed by direct mode.
61762306a36Sopenharmony_ci	 */
61862306a36Sopenharmony_ci	return false;
61962306a36Sopenharmony_ci}
62062306a36Sopenharmony_ci
62162306a36Sopenharmony_cistatic inline size_t mtr_bufs_size(struct hns_roce_buf_attr *attr)
62262306a36Sopenharmony_ci{
62362306a36Sopenharmony_ci	size_t size = 0;
62462306a36Sopenharmony_ci	int i;
62562306a36Sopenharmony_ci
62662306a36Sopenharmony_ci	for (i = 0; i < attr->region_count; i++)
62762306a36Sopenharmony_ci		size += attr->region[i].size;
62862306a36Sopenharmony_ci
62962306a36Sopenharmony_ci	return size;
63062306a36Sopenharmony_ci}
63162306a36Sopenharmony_ci
63262306a36Sopenharmony_ci/*
63362306a36Sopenharmony_ci * check the given pages in continuous address space
63462306a36Sopenharmony_ci * Returns 0 on success, or the error page num.
63562306a36Sopenharmony_ci */
63662306a36Sopenharmony_cistatic inline int mtr_check_direct_pages(dma_addr_t *pages, int page_count,
63762306a36Sopenharmony_ci					 unsigned int page_shift)
63862306a36Sopenharmony_ci{
63962306a36Sopenharmony_ci	size_t page_size = 1 << page_shift;
64062306a36Sopenharmony_ci	int i;
64162306a36Sopenharmony_ci
64262306a36Sopenharmony_ci	for (i = 1; i < page_count; i++)
64362306a36Sopenharmony_ci		if (pages[i] - pages[i - 1] != page_size)
64462306a36Sopenharmony_ci			return i;
64562306a36Sopenharmony_ci
64662306a36Sopenharmony_ci	return 0;
64762306a36Sopenharmony_ci}
64862306a36Sopenharmony_ci
64962306a36Sopenharmony_cistatic void mtr_free_bufs(struct hns_roce_dev *hr_dev, struct hns_roce_mtr *mtr)
65062306a36Sopenharmony_ci{
65162306a36Sopenharmony_ci	/* release user buffers */
65262306a36Sopenharmony_ci	if (mtr->umem) {
65362306a36Sopenharmony_ci		ib_umem_release(mtr->umem);
65462306a36Sopenharmony_ci		mtr->umem = NULL;
65562306a36Sopenharmony_ci	}
65662306a36Sopenharmony_ci
65762306a36Sopenharmony_ci	/* release kernel buffers */
65862306a36Sopenharmony_ci	if (mtr->kmem) {
65962306a36Sopenharmony_ci		hns_roce_buf_free(hr_dev, mtr->kmem);
66062306a36Sopenharmony_ci		mtr->kmem = NULL;
66162306a36Sopenharmony_ci	}
66262306a36Sopenharmony_ci}
66362306a36Sopenharmony_ci
66462306a36Sopenharmony_cistatic int mtr_alloc_bufs(struct hns_roce_dev *hr_dev, struct hns_roce_mtr *mtr,
66562306a36Sopenharmony_ci			  struct hns_roce_buf_attr *buf_attr,
66662306a36Sopenharmony_ci			  struct ib_udata *udata, unsigned long user_addr)
66762306a36Sopenharmony_ci{
66862306a36Sopenharmony_ci	struct ib_device *ibdev = &hr_dev->ib_dev;
66962306a36Sopenharmony_ci	size_t total_size;
67062306a36Sopenharmony_ci
67162306a36Sopenharmony_ci	total_size = mtr_bufs_size(buf_attr);
67262306a36Sopenharmony_ci
67362306a36Sopenharmony_ci	if (udata) {
67462306a36Sopenharmony_ci		mtr->kmem = NULL;
67562306a36Sopenharmony_ci		mtr->umem = ib_umem_get(ibdev, user_addr, total_size,
67662306a36Sopenharmony_ci					buf_attr->user_access);
67762306a36Sopenharmony_ci		if (IS_ERR_OR_NULL(mtr->umem)) {
67862306a36Sopenharmony_ci			ibdev_err(ibdev, "failed to get umem, ret = %ld.\n",
67962306a36Sopenharmony_ci				  PTR_ERR(mtr->umem));
68062306a36Sopenharmony_ci			return -ENOMEM;
68162306a36Sopenharmony_ci		}
68262306a36Sopenharmony_ci	} else {
68362306a36Sopenharmony_ci		mtr->umem = NULL;
68462306a36Sopenharmony_ci		mtr->kmem = hns_roce_buf_alloc(hr_dev, total_size,
68562306a36Sopenharmony_ci					       buf_attr->page_shift,
68662306a36Sopenharmony_ci					       mtr->hem_cfg.is_direct ?
68762306a36Sopenharmony_ci					       HNS_ROCE_BUF_DIRECT : 0);
68862306a36Sopenharmony_ci		if (IS_ERR(mtr->kmem)) {
68962306a36Sopenharmony_ci			ibdev_err(ibdev, "failed to alloc kmem, ret = %ld.\n",
69062306a36Sopenharmony_ci				  PTR_ERR(mtr->kmem));
69162306a36Sopenharmony_ci			return PTR_ERR(mtr->kmem);
69262306a36Sopenharmony_ci		}
69362306a36Sopenharmony_ci	}
69462306a36Sopenharmony_ci
69562306a36Sopenharmony_ci	return 0;
69662306a36Sopenharmony_ci}
69762306a36Sopenharmony_ci
69862306a36Sopenharmony_cistatic int mtr_map_bufs(struct hns_roce_dev *hr_dev, struct hns_roce_mtr *mtr,
69962306a36Sopenharmony_ci			int page_count, unsigned int page_shift)
70062306a36Sopenharmony_ci{
70162306a36Sopenharmony_ci	struct ib_device *ibdev = &hr_dev->ib_dev;
70262306a36Sopenharmony_ci	dma_addr_t *pages;
70362306a36Sopenharmony_ci	int npage;
70462306a36Sopenharmony_ci	int ret;
70562306a36Sopenharmony_ci
70662306a36Sopenharmony_ci	/* alloc a tmp array to store buffer's dma address */
70762306a36Sopenharmony_ci	pages = kvcalloc(page_count, sizeof(dma_addr_t), GFP_KERNEL);
70862306a36Sopenharmony_ci	if (!pages)
70962306a36Sopenharmony_ci		return -ENOMEM;
71062306a36Sopenharmony_ci
71162306a36Sopenharmony_ci	if (mtr->umem)
71262306a36Sopenharmony_ci		npage = hns_roce_get_umem_bufs(hr_dev, pages, page_count,
71362306a36Sopenharmony_ci					       mtr->umem, page_shift);
71462306a36Sopenharmony_ci	else
71562306a36Sopenharmony_ci		npage = hns_roce_get_kmem_bufs(hr_dev, pages, page_count,
71662306a36Sopenharmony_ci					       mtr->kmem, page_shift);
71762306a36Sopenharmony_ci
71862306a36Sopenharmony_ci	if (npage != page_count) {
71962306a36Sopenharmony_ci		ibdev_err(ibdev, "failed to get mtr page %d != %d.\n", npage,
72062306a36Sopenharmony_ci			  page_count);
72162306a36Sopenharmony_ci		ret = -ENOBUFS;
72262306a36Sopenharmony_ci		goto err_alloc_list;
72362306a36Sopenharmony_ci	}
72462306a36Sopenharmony_ci
72562306a36Sopenharmony_ci	if (mtr->hem_cfg.is_direct && npage > 1) {
72662306a36Sopenharmony_ci		ret = mtr_check_direct_pages(pages, npage, page_shift);
72762306a36Sopenharmony_ci		if (ret) {
72862306a36Sopenharmony_ci			ibdev_err(ibdev, "failed to check %s page: %d / %d.\n",
72962306a36Sopenharmony_ci				  mtr->umem ? "umtr" : "kmtr", ret, npage);
73062306a36Sopenharmony_ci			ret = -ENOBUFS;
73162306a36Sopenharmony_ci			goto err_alloc_list;
73262306a36Sopenharmony_ci		}
73362306a36Sopenharmony_ci	}
73462306a36Sopenharmony_ci
73562306a36Sopenharmony_ci	ret = hns_roce_mtr_map(hr_dev, mtr, pages, page_count);
73662306a36Sopenharmony_ci	if (ret)
73762306a36Sopenharmony_ci		ibdev_err(ibdev, "failed to map mtr pages, ret = %d.\n", ret);
73862306a36Sopenharmony_ci
73962306a36Sopenharmony_cierr_alloc_list:
74062306a36Sopenharmony_ci	kvfree(pages);
74162306a36Sopenharmony_ci
74262306a36Sopenharmony_ci	return ret;
74362306a36Sopenharmony_ci}
74462306a36Sopenharmony_ci
74562306a36Sopenharmony_ciint hns_roce_mtr_map(struct hns_roce_dev *hr_dev, struct hns_roce_mtr *mtr,
74662306a36Sopenharmony_ci		     dma_addr_t *pages, unsigned int page_cnt)
74762306a36Sopenharmony_ci{
74862306a36Sopenharmony_ci	struct ib_device *ibdev = &hr_dev->ib_dev;
74962306a36Sopenharmony_ci	struct hns_roce_buf_region *r;
75062306a36Sopenharmony_ci	unsigned int i, mapped_cnt;
75162306a36Sopenharmony_ci	int ret = 0;
75262306a36Sopenharmony_ci
75362306a36Sopenharmony_ci	/*
75462306a36Sopenharmony_ci	 * Only use the first page address as root ba when hopnum is 0, this
75562306a36Sopenharmony_ci	 * is because the addresses of all pages are consecutive in this case.
75662306a36Sopenharmony_ci	 */
75762306a36Sopenharmony_ci	if (mtr->hem_cfg.is_direct) {
75862306a36Sopenharmony_ci		mtr->hem_cfg.root_ba = pages[0];
75962306a36Sopenharmony_ci		return 0;
76062306a36Sopenharmony_ci	}
76162306a36Sopenharmony_ci
76262306a36Sopenharmony_ci	for (i = 0, mapped_cnt = 0; i < mtr->hem_cfg.region_count &&
76362306a36Sopenharmony_ci	     mapped_cnt < page_cnt; i++) {
76462306a36Sopenharmony_ci		r = &mtr->hem_cfg.region[i];
76562306a36Sopenharmony_ci		/* if hopnum is 0, no need to map pages in this region */
76662306a36Sopenharmony_ci		if (!r->hopnum) {
76762306a36Sopenharmony_ci			mapped_cnt += r->count;
76862306a36Sopenharmony_ci			continue;
76962306a36Sopenharmony_ci		}
77062306a36Sopenharmony_ci
77162306a36Sopenharmony_ci		if (r->offset + r->count > page_cnt) {
77262306a36Sopenharmony_ci			ret = -EINVAL;
77362306a36Sopenharmony_ci			ibdev_err(ibdev,
77462306a36Sopenharmony_ci				  "failed to check mtr%u count %u + %u > %u.\n",
77562306a36Sopenharmony_ci				  i, r->offset, r->count, page_cnt);
77662306a36Sopenharmony_ci			return ret;
77762306a36Sopenharmony_ci		}
77862306a36Sopenharmony_ci
77962306a36Sopenharmony_ci		ret = mtr_map_region(hr_dev, mtr, r, &pages[r->offset],
78062306a36Sopenharmony_ci				     page_cnt - mapped_cnt);
78162306a36Sopenharmony_ci		if (ret < 0) {
78262306a36Sopenharmony_ci			ibdev_err(ibdev,
78362306a36Sopenharmony_ci				  "failed to map mtr%u offset %u, ret = %d.\n",
78462306a36Sopenharmony_ci				  i, r->offset, ret);
78562306a36Sopenharmony_ci			return ret;
78662306a36Sopenharmony_ci		}
78762306a36Sopenharmony_ci		mapped_cnt += ret;
78862306a36Sopenharmony_ci		ret = 0;
78962306a36Sopenharmony_ci	}
79062306a36Sopenharmony_ci
79162306a36Sopenharmony_ci	if (mapped_cnt < page_cnt) {
79262306a36Sopenharmony_ci		ret = -ENOBUFS;
79362306a36Sopenharmony_ci		ibdev_err(ibdev, "failed to map mtr pages count: %u < %u.\n",
79462306a36Sopenharmony_ci			  mapped_cnt, page_cnt);
79562306a36Sopenharmony_ci	}
79662306a36Sopenharmony_ci
79762306a36Sopenharmony_ci	return ret;
79862306a36Sopenharmony_ci}
79962306a36Sopenharmony_ci
80062306a36Sopenharmony_ciint hns_roce_mtr_find(struct hns_roce_dev *hr_dev, struct hns_roce_mtr *mtr,
80162306a36Sopenharmony_ci		      u32 offset, u64 *mtt_buf, int mtt_max, u64 *base_addr)
80262306a36Sopenharmony_ci{
80362306a36Sopenharmony_ci	struct hns_roce_hem_cfg *cfg = &mtr->hem_cfg;
80462306a36Sopenharmony_ci	int mtt_count, left;
80562306a36Sopenharmony_ci	u32 start_index;
80662306a36Sopenharmony_ci	int total = 0;
80762306a36Sopenharmony_ci	__le64 *mtts;
80862306a36Sopenharmony_ci	u32 npage;
80962306a36Sopenharmony_ci	u64 addr;
81062306a36Sopenharmony_ci
81162306a36Sopenharmony_ci	if (!mtt_buf || mtt_max < 1)
81262306a36Sopenharmony_ci		goto done;
81362306a36Sopenharmony_ci
81462306a36Sopenharmony_ci	/* no mtt memory in direct mode, so just return the buffer address */
81562306a36Sopenharmony_ci	if (cfg->is_direct) {
81662306a36Sopenharmony_ci		start_index = offset >> HNS_HW_PAGE_SHIFT;
81762306a36Sopenharmony_ci		for (mtt_count = 0; mtt_count < cfg->region_count &&
81862306a36Sopenharmony_ci		     total < mtt_max; mtt_count++) {
81962306a36Sopenharmony_ci			npage = cfg->region[mtt_count].offset;
82062306a36Sopenharmony_ci			if (npage < start_index)
82162306a36Sopenharmony_ci				continue;
82262306a36Sopenharmony_ci
82362306a36Sopenharmony_ci			addr = cfg->root_ba + (npage << HNS_HW_PAGE_SHIFT);
82462306a36Sopenharmony_ci			mtt_buf[total] = addr;
82562306a36Sopenharmony_ci
82662306a36Sopenharmony_ci			total++;
82762306a36Sopenharmony_ci		}
82862306a36Sopenharmony_ci
82962306a36Sopenharmony_ci		goto done;
83062306a36Sopenharmony_ci	}
83162306a36Sopenharmony_ci
83262306a36Sopenharmony_ci	start_index = offset >> cfg->buf_pg_shift;
83362306a36Sopenharmony_ci	left = mtt_max;
83462306a36Sopenharmony_ci	while (left > 0) {
83562306a36Sopenharmony_ci		mtt_count = 0;
83662306a36Sopenharmony_ci		mtts = hns_roce_hem_list_find_mtt(hr_dev, &mtr->hem_list,
83762306a36Sopenharmony_ci						  start_index + total,
83862306a36Sopenharmony_ci						  &mtt_count);
83962306a36Sopenharmony_ci		if (!mtts || !mtt_count)
84062306a36Sopenharmony_ci			goto done;
84162306a36Sopenharmony_ci
84262306a36Sopenharmony_ci		npage = min(mtt_count, left);
84362306a36Sopenharmony_ci		left -= npage;
84462306a36Sopenharmony_ci		for (mtt_count = 0; mtt_count < npage; mtt_count++)
84562306a36Sopenharmony_ci			mtt_buf[total++] = le64_to_cpu(mtts[mtt_count]);
84662306a36Sopenharmony_ci	}
84762306a36Sopenharmony_ci
84862306a36Sopenharmony_cidone:
84962306a36Sopenharmony_ci	if (base_addr)
85062306a36Sopenharmony_ci		*base_addr = cfg->root_ba;
85162306a36Sopenharmony_ci
85262306a36Sopenharmony_ci	return total;
85362306a36Sopenharmony_ci}
85462306a36Sopenharmony_ci
85562306a36Sopenharmony_cistatic int mtr_init_buf_cfg(struct hns_roce_dev *hr_dev,
85662306a36Sopenharmony_ci			    struct hns_roce_buf_attr *attr,
85762306a36Sopenharmony_ci			    struct hns_roce_hem_cfg *cfg,
85862306a36Sopenharmony_ci			    unsigned int *buf_page_shift, u64 unalinged_size)
85962306a36Sopenharmony_ci{
86062306a36Sopenharmony_ci	struct hns_roce_buf_region *r;
86162306a36Sopenharmony_ci	u64 first_region_padding;
86262306a36Sopenharmony_ci	int page_cnt, region_cnt;
86362306a36Sopenharmony_ci	unsigned int page_shift;
86462306a36Sopenharmony_ci	size_t buf_size;
86562306a36Sopenharmony_ci
86662306a36Sopenharmony_ci	/* If mtt is disabled, all pages must be within a continuous range */
86762306a36Sopenharmony_ci	cfg->is_direct = !mtr_has_mtt(attr);
86862306a36Sopenharmony_ci	buf_size = mtr_bufs_size(attr);
86962306a36Sopenharmony_ci	if (cfg->is_direct) {
87062306a36Sopenharmony_ci		/* When HEM buffer uses 0-level addressing, the page size is
87162306a36Sopenharmony_ci		 * equal to the whole buffer size, and we split the buffer into
87262306a36Sopenharmony_ci		 * small pages which is used to check whether the adjacent
87362306a36Sopenharmony_ci		 * units are in the continuous space and its size is fixed to
87462306a36Sopenharmony_ci		 * 4K based on hns ROCEE's requirement.
87562306a36Sopenharmony_ci		 */
87662306a36Sopenharmony_ci		page_shift = HNS_HW_PAGE_SHIFT;
87762306a36Sopenharmony_ci
87862306a36Sopenharmony_ci		/* The ROCEE requires the page size to be 4K * 2 ^ N. */
87962306a36Sopenharmony_ci		cfg->buf_pg_count = 1;
88062306a36Sopenharmony_ci		cfg->buf_pg_shift = HNS_HW_PAGE_SHIFT +
88162306a36Sopenharmony_ci			order_base_2(DIV_ROUND_UP(buf_size, HNS_HW_PAGE_SIZE));
88262306a36Sopenharmony_ci		first_region_padding = 0;
88362306a36Sopenharmony_ci	} else {
88462306a36Sopenharmony_ci		page_shift = attr->page_shift;
88562306a36Sopenharmony_ci		cfg->buf_pg_count = DIV_ROUND_UP(buf_size + unalinged_size,
88662306a36Sopenharmony_ci						 1 << page_shift);
88762306a36Sopenharmony_ci		cfg->buf_pg_shift = page_shift;
88862306a36Sopenharmony_ci		first_region_padding = unalinged_size;
88962306a36Sopenharmony_ci	}
89062306a36Sopenharmony_ci
89162306a36Sopenharmony_ci	/* Convert buffer size to page index and page count for each region and
89262306a36Sopenharmony_ci	 * the buffer's offset needs to be appended to the first region.
89362306a36Sopenharmony_ci	 */
89462306a36Sopenharmony_ci	for (page_cnt = 0, region_cnt = 0; region_cnt < attr->region_count &&
89562306a36Sopenharmony_ci	     region_cnt < ARRAY_SIZE(cfg->region); region_cnt++) {
89662306a36Sopenharmony_ci		r = &cfg->region[region_cnt];
89762306a36Sopenharmony_ci		r->offset = page_cnt;
89862306a36Sopenharmony_ci		buf_size = hr_hw_page_align(attr->region[region_cnt].size +
89962306a36Sopenharmony_ci					    first_region_padding);
90062306a36Sopenharmony_ci		r->count = DIV_ROUND_UP(buf_size, 1 << page_shift);
90162306a36Sopenharmony_ci		first_region_padding = 0;
90262306a36Sopenharmony_ci		page_cnt += r->count;
90362306a36Sopenharmony_ci		r->hopnum = to_hr_hem_hopnum(attr->region[region_cnt].hopnum,
90462306a36Sopenharmony_ci					     r->count);
90562306a36Sopenharmony_ci	}
90662306a36Sopenharmony_ci
90762306a36Sopenharmony_ci	cfg->region_count = region_cnt;
90862306a36Sopenharmony_ci	*buf_page_shift = page_shift;
90962306a36Sopenharmony_ci
91062306a36Sopenharmony_ci	return page_cnt;
91162306a36Sopenharmony_ci}
91262306a36Sopenharmony_ci
91362306a36Sopenharmony_cistatic u64 cal_pages_per_l1ba(unsigned int ba_per_bt, unsigned int hopnum)
91462306a36Sopenharmony_ci{
91562306a36Sopenharmony_ci	return int_pow(ba_per_bt, hopnum - 1);
91662306a36Sopenharmony_ci}
91762306a36Sopenharmony_ci
91862306a36Sopenharmony_cistatic unsigned int cal_best_bt_pg_sz(struct hns_roce_dev *hr_dev,
91962306a36Sopenharmony_ci				      struct hns_roce_mtr *mtr,
92062306a36Sopenharmony_ci				      unsigned int pg_shift)
92162306a36Sopenharmony_ci{
92262306a36Sopenharmony_ci	unsigned long cap = hr_dev->caps.page_size_cap;
92362306a36Sopenharmony_ci	struct hns_roce_buf_region *re;
92462306a36Sopenharmony_ci	unsigned int pgs_per_l1ba;
92562306a36Sopenharmony_ci	unsigned int ba_per_bt;
92662306a36Sopenharmony_ci	unsigned int ba_num;
92762306a36Sopenharmony_ci	int i;
92862306a36Sopenharmony_ci
92962306a36Sopenharmony_ci	for_each_set_bit_from(pg_shift, &cap, sizeof(cap) * BITS_PER_BYTE) {
93062306a36Sopenharmony_ci		if (!(BIT(pg_shift) & cap))
93162306a36Sopenharmony_ci			continue;
93262306a36Sopenharmony_ci
93362306a36Sopenharmony_ci		ba_per_bt = BIT(pg_shift) / BA_BYTE_LEN;
93462306a36Sopenharmony_ci		ba_num = 0;
93562306a36Sopenharmony_ci		for (i = 0; i < mtr->hem_cfg.region_count; i++) {
93662306a36Sopenharmony_ci			re = &mtr->hem_cfg.region[i];
93762306a36Sopenharmony_ci			if (re->hopnum == 0)
93862306a36Sopenharmony_ci				continue;
93962306a36Sopenharmony_ci
94062306a36Sopenharmony_ci			pgs_per_l1ba = cal_pages_per_l1ba(ba_per_bt, re->hopnum);
94162306a36Sopenharmony_ci			ba_num += DIV_ROUND_UP(re->count, pgs_per_l1ba);
94262306a36Sopenharmony_ci		}
94362306a36Sopenharmony_ci
94462306a36Sopenharmony_ci		if (ba_num <= ba_per_bt)
94562306a36Sopenharmony_ci			return pg_shift;
94662306a36Sopenharmony_ci	}
94762306a36Sopenharmony_ci
94862306a36Sopenharmony_ci	return 0;
94962306a36Sopenharmony_ci}
95062306a36Sopenharmony_ci
95162306a36Sopenharmony_cistatic int mtr_alloc_mtt(struct hns_roce_dev *hr_dev, struct hns_roce_mtr *mtr,
95262306a36Sopenharmony_ci			 unsigned int ba_page_shift)
95362306a36Sopenharmony_ci{
95462306a36Sopenharmony_ci	struct hns_roce_hem_cfg *cfg = &mtr->hem_cfg;
95562306a36Sopenharmony_ci	int ret;
95662306a36Sopenharmony_ci
95762306a36Sopenharmony_ci	hns_roce_hem_list_init(&mtr->hem_list);
95862306a36Sopenharmony_ci	if (!cfg->is_direct) {
95962306a36Sopenharmony_ci		ba_page_shift = cal_best_bt_pg_sz(hr_dev, mtr, ba_page_shift);
96062306a36Sopenharmony_ci		if (!ba_page_shift)
96162306a36Sopenharmony_ci			return -ERANGE;
96262306a36Sopenharmony_ci
96362306a36Sopenharmony_ci		ret = hns_roce_hem_list_request(hr_dev, &mtr->hem_list,
96462306a36Sopenharmony_ci						cfg->region, cfg->region_count,
96562306a36Sopenharmony_ci						ba_page_shift);
96662306a36Sopenharmony_ci		if (ret)
96762306a36Sopenharmony_ci			return ret;
96862306a36Sopenharmony_ci		cfg->root_ba = mtr->hem_list.root_ba;
96962306a36Sopenharmony_ci		cfg->ba_pg_shift = ba_page_shift;
97062306a36Sopenharmony_ci	} else {
97162306a36Sopenharmony_ci		cfg->ba_pg_shift = cfg->buf_pg_shift;
97262306a36Sopenharmony_ci	}
97362306a36Sopenharmony_ci
97462306a36Sopenharmony_ci	return 0;
97562306a36Sopenharmony_ci}
97662306a36Sopenharmony_ci
97762306a36Sopenharmony_cistatic void mtr_free_mtt(struct hns_roce_dev *hr_dev, struct hns_roce_mtr *mtr)
97862306a36Sopenharmony_ci{
97962306a36Sopenharmony_ci	hns_roce_hem_list_release(hr_dev, &mtr->hem_list);
98062306a36Sopenharmony_ci}
98162306a36Sopenharmony_ci
98262306a36Sopenharmony_ci/**
98362306a36Sopenharmony_ci * hns_roce_mtr_create - Create hns memory translate region.
98462306a36Sopenharmony_ci *
98562306a36Sopenharmony_ci * @hr_dev: RoCE device struct pointer
98662306a36Sopenharmony_ci * @mtr: memory translate region
98762306a36Sopenharmony_ci * @buf_attr: buffer attribute for creating mtr
98862306a36Sopenharmony_ci * @ba_page_shift: page shift for multi-hop base address table
98962306a36Sopenharmony_ci * @udata: user space context, if it's NULL, means kernel space
99062306a36Sopenharmony_ci * @user_addr: userspace virtual address to start at
99162306a36Sopenharmony_ci */
99262306a36Sopenharmony_ciint hns_roce_mtr_create(struct hns_roce_dev *hr_dev, struct hns_roce_mtr *mtr,
99362306a36Sopenharmony_ci			struct hns_roce_buf_attr *buf_attr,
99462306a36Sopenharmony_ci			unsigned int ba_page_shift, struct ib_udata *udata,
99562306a36Sopenharmony_ci			unsigned long user_addr)
99662306a36Sopenharmony_ci{
99762306a36Sopenharmony_ci	struct ib_device *ibdev = &hr_dev->ib_dev;
99862306a36Sopenharmony_ci	unsigned int buf_page_shift = 0;
99962306a36Sopenharmony_ci	int buf_page_cnt;
100062306a36Sopenharmony_ci	int ret;
100162306a36Sopenharmony_ci
100262306a36Sopenharmony_ci	buf_page_cnt = mtr_init_buf_cfg(hr_dev, buf_attr, &mtr->hem_cfg,
100362306a36Sopenharmony_ci					&buf_page_shift,
100462306a36Sopenharmony_ci					udata ? user_addr & ~PAGE_MASK : 0);
100562306a36Sopenharmony_ci	if (buf_page_cnt < 1 || buf_page_shift < HNS_HW_PAGE_SHIFT) {
100662306a36Sopenharmony_ci		ibdev_err(ibdev, "failed to init mtr cfg, count %d shift %u.\n",
100762306a36Sopenharmony_ci			  buf_page_cnt, buf_page_shift);
100862306a36Sopenharmony_ci		return -EINVAL;
100962306a36Sopenharmony_ci	}
101062306a36Sopenharmony_ci
101162306a36Sopenharmony_ci	ret = mtr_alloc_mtt(hr_dev, mtr, ba_page_shift);
101262306a36Sopenharmony_ci	if (ret) {
101362306a36Sopenharmony_ci		ibdev_err(ibdev, "failed to alloc mtr mtt, ret = %d.\n", ret);
101462306a36Sopenharmony_ci		return ret;
101562306a36Sopenharmony_ci	}
101662306a36Sopenharmony_ci
101762306a36Sopenharmony_ci	/* The caller has its own buffer list and invokes the hns_roce_mtr_map()
101862306a36Sopenharmony_ci	 * to finish the MTT configuration.
101962306a36Sopenharmony_ci	 */
102062306a36Sopenharmony_ci	if (buf_attr->mtt_only) {
102162306a36Sopenharmony_ci		mtr->umem = NULL;
102262306a36Sopenharmony_ci		mtr->kmem = NULL;
102362306a36Sopenharmony_ci		return 0;
102462306a36Sopenharmony_ci	}
102562306a36Sopenharmony_ci
102662306a36Sopenharmony_ci	ret = mtr_alloc_bufs(hr_dev, mtr, buf_attr, udata, user_addr);
102762306a36Sopenharmony_ci	if (ret) {
102862306a36Sopenharmony_ci		ibdev_err(ibdev, "failed to alloc mtr bufs, ret = %d.\n", ret);
102962306a36Sopenharmony_ci		goto err_alloc_mtt;
103062306a36Sopenharmony_ci	}
103162306a36Sopenharmony_ci
103262306a36Sopenharmony_ci	/* Write buffer's dma address to MTT */
103362306a36Sopenharmony_ci	ret = mtr_map_bufs(hr_dev, mtr, buf_page_cnt, buf_page_shift);
103462306a36Sopenharmony_ci	if (ret)
103562306a36Sopenharmony_ci		ibdev_err(ibdev, "failed to map mtr bufs, ret = %d.\n", ret);
103662306a36Sopenharmony_ci	else
103762306a36Sopenharmony_ci		return 0;
103862306a36Sopenharmony_ci
103962306a36Sopenharmony_ci	mtr_free_bufs(hr_dev, mtr);
104062306a36Sopenharmony_cierr_alloc_mtt:
104162306a36Sopenharmony_ci	mtr_free_mtt(hr_dev, mtr);
104262306a36Sopenharmony_ci	return ret;
104362306a36Sopenharmony_ci}
104462306a36Sopenharmony_ci
104562306a36Sopenharmony_civoid hns_roce_mtr_destroy(struct hns_roce_dev *hr_dev, struct hns_roce_mtr *mtr)
104662306a36Sopenharmony_ci{
104762306a36Sopenharmony_ci	/* release multi-hop addressing resource */
104862306a36Sopenharmony_ci	hns_roce_hem_list_release(hr_dev, &mtr->hem_list);
104962306a36Sopenharmony_ci
105062306a36Sopenharmony_ci	/* free buffers */
105162306a36Sopenharmony_ci	mtr_free_bufs(hr_dev, mtr);
105262306a36Sopenharmony_ci}
1053