RDMA/hns: Add check for SL
authorLuoyouming <luoyouming@huawei.com>
Tue, 17 Oct 2023 12:52:36 +0000 (20:52 +0800)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Mon, 20 Nov 2023 10:59:21 +0000 (11:59 +0100)
[ Upstream commit 5e617c18b1f34ec57ad5dce44f09de603cf6bd6c ]

SL set by users may exceed the capability of devices. So add check
for this situation.

Fixes: fba429fcf9a5 ("RDMA/hns: Fix missing fields in address vector")
Fixes: 70f92521584f ("RDMA/hns: Use the reserved loopback QPs to free MR before destroying MPT")
Fixes: f0cb411aad23 ("RDMA/hns: Use new interface to modify QP context")
Signed-off-by: Luoyouming <luoyouming@huawei.com>
Signed-off-by: Junxian Huang <huangjunxian6@hisilicon.com>
Link: https://lore.kernel.org/r/20231017125239.164455-5-huangjunxian6@hisilicon.com
Signed-off-by: Leon Romanovsky <leon@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
drivers/infiniband/hw/hns/hns_roce_ah.c
drivers/infiniband/hw/hns/hns_roce_hw_v2.c

index e77fcc7..3df032d 100644 (file)
@@ -33,7 +33,9 @@
 #include <linux/pci.h>
 #include <rdma/ib_addr.h>
 #include <rdma/ib_cache.h>
+#include "hnae3.h"
 #include "hns_roce_device.h"
+#include "hns_roce_hw_v2.h"
 
 static inline u16 get_ah_udp_sport(const struct rdma_ah_attr *ah_attr)
 {
@@ -57,6 +59,7 @@ int hns_roce_create_ah(struct ib_ah *ibah, struct rdma_ah_init_attr *init_attr,
        struct hns_roce_dev *hr_dev = to_hr_dev(ibah->device);
        struct hns_roce_ah *ah = to_hr_ah(ibah);
        int ret = 0;
+       u32 max_sl;
 
        if (hr_dev->pci_dev->revision == PCI_REVISION_ID_HIP08 && udata)
                return -EOPNOTSUPP;
@@ -70,9 +73,17 @@ int hns_roce_create_ah(struct ib_ah *ibah, struct rdma_ah_init_attr *init_attr,
        ah->av.hop_limit = grh->hop_limit;
        ah->av.flowlabel = grh->flow_label;
        ah->av.udp_sport = get_ah_udp_sport(ah_attr);
-       ah->av.sl = rdma_ah_get_sl(ah_attr);
        ah->av.tclass = get_tclass(grh);
 
+       ah->av.sl = rdma_ah_get_sl(ah_attr);
+       max_sl = min_t(u32, MAX_SERVICE_LEVEL, hr_dev->caps.sl_num - 1);
+       if (unlikely(ah->av.sl > max_sl)) {
+               ibdev_err_ratelimited(&hr_dev->ib_dev,
+                                     "failed to set sl, sl (%u) shouldn't be larger than %u.\n",
+                                     ah->av.sl, max_sl);
+               return -EINVAL;
+       }
+
        memcpy(ah->av.dgid, grh->dgid.raw, HNS_ROCE_GID_SIZE);
        memcpy(ah->av.mac, ah_attr->roce.dmac, ETH_ALEN);
 
index 3daa684..b7faf5c 100644 (file)
@@ -4821,22 +4821,32 @@ static int hns_roce_v2_set_path(struct ib_qp *ibqp,
        struct hns_roce_qp *hr_qp = to_hr_qp(ibqp);
        struct ib_device *ibdev = &hr_dev->ib_dev;
        const struct ib_gid_attr *gid_attr = NULL;
+       u8 sl = rdma_ah_get_sl(&attr->ah_attr);
        int is_roce_protocol;
        u16 vlan_id = 0xffff;
        bool is_udp = false;
+       u32 max_sl;
        u8 ib_port;
        u8 hr_port;
        int ret;
 
+       max_sl = min_t(u32, MAX_SERVICE_LEVEL, hr_dev->caps.sl_num - 1);
+       if (unlikely(sl > max_sl)) {
+               ibdev_err_ratelimited(ibdev,
+                                     "failed to fill QPC, sl (%u) shouldn't be larger than %u.\n",
+                                     sl, max_sl);
+               return -EINVAL;
+       }
+
        /*
         * If free_mr_en of qp is set, it means that this qp comes from
         * free mr. This qp will perform the loopback operation.
         * In the loopback scenario, only sl needs to be set.
         */
        if (hr_qp->free_mr_en) {
-               hr_reg_write(context, QPC_SL, rdma_ah_get_sl(&attr->ah_attr));
+               hr_reg_write(context, QPC_SL, sl);
                hr_reg_clear(qpc_mask, QPC_SL);
-               hr_qp->sl = rdma_ah_get_sl(&attr->ah_attr);
+               hr_qp->sl = sl;
                return 0;
        }
 
@@ -4903,14 +4913,7 @@ static int hns_roce_v2_set_path(struct ib_qp *ibqp,
        memcpy(context->dgid, grh->dgid.raw, sizeof(grh->dgid.raw));
        memset(qpc_mask->dgid, 0, sizeof(grh->dgid.raw));
 
-       hr_qp->sl = rdma_ah_get_sl(&attr->ah_attr);
-       if (unlikely(hr_qp->sl > MAX_SERVICE_LEVEL)) {
-               ibdev_err(ibdev,
-                         "failed to fill QPC, sl (%u) shouldn't be larger than %d.\n",
-                         hr_qp->sl, MAX_SERVICE_LEVEL);
-               return -EINVAL;
-       }
-
+       hr_qp->sl = sl;
        hr_reg_write(context, QPC_SL, hr_qp->sl);
        hr_reg_clear(qpc_mask, QPC_SL);