]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
RDMA/hns: Fix mapping error of zero-hop WQE buffer
authorwenglianfa <wenglianfa@huawei.com>
Fri, 20 Dec 2024 05:52:46 +0000 (13:52 +0800)
committerLeon Romanovsky <leon@kernel.org>
Mon, 23 Dec 2024 14:58:30 +0000 (09:58 -0500)
Due to HW limitation, the three region of WQE buffer must be mapped
and set to HW in a fixed order: SQ buffer, SGE buffer, and RQ buffer.

Currently when one region is zero-hop while the other two are not,
the zero-hop region will not be mapped. This violate the limitation
above and leads to address error.

Fixes: 38389eaa4db1 ("RDMA/hns: Add mtr support for mixed multihop addressing")
Signed-off-by: wenglianfa <wenglianfa@huawei.com>
Signed-off-by: Junxian Huang <huangjunxian6@hisilicon.com>
Link: https://patch.msgid.link/20241220055249.146943-2-huangjunxian6@hisilicon.com
Signed-off-by: Leon Romanovsky <leon@kernel.org>
drivers/infiniband/hw/hns/hns_roce_hem.c
drivers/infiniband/hw/hns/hns_roce_mr.c

index f84521be3bea4ac514769cab1bcdb5765a70ea11..605562122ecce2bde17b0621970bd20cbf720025 100644 (file)
@@ -931,6 +931,7 @@ struct hns_roce_hem_item {
        size_t count; /* max ba numbers */
        int start; /* start buf offset in this hem */
        int end; /* end buf offset in this hem */
+       bool exist_bt;
 };
 
 /* All HEM items are linked in a tree structure */
@@ -959,6 +960,7 @@ hem_list_alloc_item(struct hns_roce_dev *hr_dev, int start, int end, int count,
                }
        }
 
+       hem->exist_bt = exist_bt;
        hem->count = count;
        hem->start = start;
        hem->end = end;
@@ -969,22 +971,22 @@ hem_list_alloc_item(struct hns_roce_dev *hr_dev, int start, int end, int count,
 }
 
 static void hem_list_free_item(struct hns_roce_dev *hr_dev,
-                              struct hns_roce_hem_item *hem, bool exist_bt)
+                              struct hns_roce_hem_item *hem)
 {
-       if (exist_bt)
+       if (hem->exist_bt)
                dma_free_coherent(hr_dev->dev, hem->count * BA_BYTE_LEN,
                                  hem->addr, hem->dma_addr);
        kfree(hem);
 }
 
 static void hem_list_free_all(struct hns_roce_dev *hr_dev,
-                             struct list_head *head, bool exist_bt)
+                             struct list_head *head)
 {
        struct hns_roce_hem_item *hem, *temp_hem;
 
        list_for_each_entry_safe(hem, temp_hem, head, list) {
                list_del(&hem->list);
-               hem_list_free_item(hr_dev, hem, exist_bt);
+               hem_list_free_item(hr_dev, hem);
        }
 }
 
@@ -1084,6 +1086,10 @@ int hns_roce_hem_list_calc_root_ba(const struct hns_roce_buf_region *regions,
 
        for (i = 0; i < region_cnt; i++) {
                r = (struct hns_roce_buf_region *)&regions[i];
+               /* when r->hopnum = 0, the region should not occupy root_ba. */
+               if (!r->hopnum)
+                       continue;
+
                if (r->hopnum > 1) {
                        step = hem_list_calc_ba_range(r->hopnum, 1, unit);
                        if (step > 0)
@@ -1177,7 +1183,7 @@ static int hem_list_alloc_mid_bt(struct hns_roce_dev *hr_dev,
 
 err_exit:
        for (level = 1; level < hopnum; level++)
-               hem_list_free_all(hr_dev, &temp_list[level], true);
+               hem_list_free_all(hr_dev, &temp_list[level]);
 
        return ret;
 }
@@ -1218,16 +1224,26 @@ static int alloc_fake_root_bt(struct hns_roce_dev *hr_dev, void *cpu_base,
 {
        struct hns_roce_hem_item *hem;
 
+       /* This is on the has_mtt branch, if r->hopnum
+        * is 0, there is no root_ba to reuse for the
+        * region's fake hem, so a dma_alloc request is
+        * necessary here.
+        */
        hem = hem_list_alloc_item(hr_dev, r->offset, r->offset + r->count - 1,
-                                 r->count, false);
+                                 r->count, !r->hopnum);
        if (!hem)
                return -ENOMEM;
 
-       hem_list_assign_bt(hem, cpu_base, phy_base);
+       /* The root_ba can be reused only when r->hopnum > 0. */
+       if (r->hopnum)
+               hem_list_assign_bt(hem, cpu_base, phy_base);
        list_add(&hem->list, branch_head);
        list_add(&hem->sibling, leaf_head);
 
-       return r->count;
+       /* If r->hopnum == 0, 0 is returned,
+        * so that the root_bt entry is not occupied.
+        */
+       return r->hopnum ? r->count : 0;
 }
 
 static int setup_middle_bt(struct hns_roce_dev *hr_dev, void *cpu_base,
@@ -1271,7 +1287,7 @@ setup_root_hem(struct hns_roce_dev *hr_dev, struct hns_roce_hem_list *hem_list,
                return -ENOMEM;
 
        total = 0;
-       for (i = 0; i < region_cnt && total < max_ba_num; i++) {
+       for (i = 0; i < region_cnt && total <= max_ba_num; i++) {
                r = &regions[i];
                if (!r->count)
                        continue;
@@ -1337,9 +1353,9 @@ static int hem_list_alloc_root_bt(struct hns_roce_dev *hr_dev,
                             region_cnt);
        if (ret) {
                for (i = 0; i < region_cnt; i++)
-                       hem_list_free_all(hr_dev, &head.branch[i], false);
+                       hem_list_free_all(hr_dev, &head.branch[i]);
 
-               hem_list_free_all(hr_dev, &head.root, true);
+               hem_list_free_all(hr_dev, &head.root);
        }
 
        return ret;
@@ -1402,10 +1418,9 @@ void hns_roce_hem_list_release(struct hns_roce_dev *hr_dev,
 
        for (i = 0; i < HNS_ROCE_MAX_BT_REGION; i++)
                for (j = 0; j < HNS_ROCE_MAX_BT_LEVEL; j++)
-                       hem_list_free_all(hr_dev, &hem_list->mid_bt[i][j],
-                                         j != 0);
+                       hem_list_free_all(hr_dev, &hem_list->mid_bt[i][j]);
 
-       hem_list_free_all(hr_dev, &hem_list->root_bt, true);
+       hem_list_free_all(hr_dev, &hem_list->root_bt);
        INIT_LIST_HEAD(&hem_list->btm_bt);
        hem_list->root_ba = 0;
 }
index bf30b3a65a9ba908716641b83b73d70c5eff9766..55b9283bfc6f030f874955aede1992225aed2f0e 100644 (file)
@@ -814,11 +814,6 @@ int hns_roce_mtr_map(struct hns_roce_dev *hr_dev, struct hns_roce_mtr *mtr,
        for (i = 0, mapped_cnt = 0; i < mtr->hem_cfg.region_count &&
             mapped_cnt < page_cnt; i++) {
                r = &mtr->hem_cfg.region[i];
-               /* if hopnum is 0, no need to map pages in this region */
-               if (!r->hopnum) {
-                       mapped_cnt += r->count;
-                       continue;
-               }
 
                if (r->offset + r->count > page_cnt) {
                        ret = -EINVAL;