From 0baa48ea4899d0e08b450aa7e1bd7016094f52c8 Mon Sep 17 00:00:00 2001 From: Dazhao Lao Date: Tue, 20 Aug 2024 16:55:16 +0800 Subject: [PATCH 1/4] [PATCH OLK-5.10] RDMA/hns: Support query FW cap bit driver inclusion category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/IAL7SX ---------------------------------------------------------------------- The driver does not know which functions are supported by the FW, which may cause compatibility problems. When the new driver matches the old firmware, the firmware returns a success message for unsupported commands, which may cause misunderstanding. Signed-off-by: Dazhao Lao Reviewed-by: Ke Chen --- drivers/infiniband/hw/hns/hns_roce_device.h | 1 + drivers/infiniband/hw/hns/hns_roce_hw_v2.c | 1 + drivers/infiniband/hw/hns/hns_roce_hw_v2.h | 4 +++- 3 files changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/infiniband/hw/hns/hns_roce_device.h b/drivers/infiniband/hw/hns/hns_roce_device.h index 0bad0165aa21..c859c0e5c807 100644 --- a/drivers/infiniband/hw/hns/hns_roce_device.h +++ b/drivers/infiniband/hw/hns/hns_roce_device.h @@ -983,6 +983,7 @@ struct hns_roce_caps { u8 congest_type; u8 default_congest_type; u8 poe_ch_num; + u32 fw_cap; }; enum hns_roce_device_state { diff --git a/drivers/infiniband/hw/hns/hns_roce_hw_v2.c b/drivers/infiniband/hw/hns/hns_roce_hw_v2.c index d7fba8f7ceb4..0ddece06f505 100644 --- a/drivers/infiniband/hw/hns/hns_roce_hw_v2.c +++ b/drivers/infiniband/hw/hns/hns_roce_hw_v2.c @@ -1822,6 +1822,7 @@ static int hns_roce_query_fw_ver(struct hns_roce_dev *hr_dev) resp = (struct hns_roce_query_fw_info *)desc.data; hr_dev->caps.fw_ver = (u64)(le32_to_cpu(resp->fw_ver)); + hr_dev->caps.fw_cap = le32_to_cpu(resp->fw_cap); return 0; } diff --git a/drivers/infiniband/hw/hns/hns_roce_hw_v2.h b/drivers/infiniband/hw/hns/hns_roce_hw_v2.h index 81db36b14153..48c86b1a211c 100644 --- a/drivers/infiniband/hw/hns/hns_roce_hw_v2.h +++ b/drivers/infiniband/hw/hns/hns_roce_hw_v2.h @@ -1008,7 +1008,9 @@ struct hns_roce_query_version { struct hns_roce_query_fw_info { __le32 fw_ver; - __le32 rsv[5]; + __le32 rsv[3]; + __le32 fw_cap; + __le32 rsv1[1]; }; struct hns_roce_func_clear { -- Gitee From e8e3f2da005e88c5bc9e6095a411cd295113af52 Mon Sep 17 00:00:00 2001 From: Dazhao Lao Date: Tue, 20 Aug 2024 19:59:10 +0800 Subject: [PATCH 2/4] [PATCH OLK-5.10] RDMA/hns: Support configure and query the CNP DSCP through sysfs driver inclusion category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/IAL7SX ---------------------------------------------------------------------- Support configure and query the CNP DSCP through sysfs. example: $ echo 1 > /sys/class/infiniband/hns_2/ports/1/cc_param/cnp_pri_param/ enable $ cat /sys/class/infiniband/hns_2/ports/1/cc_param/cnp_pri_param/enable $ 1 $ echo 22 > /sys/class/infiniband/hns_2/ports/1/cc_param/cnp_pri_param/dscp $ cat /sys/class/infiniband/hns_2/ports/1/cc_param/cnp_pri_param/dscp $ 22 Restriction 1.Only HIP10 is supported. 2.Only the main PF is supported. 3.ROH only. 4.The DSCP value ranges from 0 to 63. The default value is 0. 5.The CNP enabling value has two enable values: 0 (select from the QPC) and 1 (select from this configuration). The default value is 0. 6.When the CNP DSCP configuration enabling value is 0, the configured DSCP value is invalid and the error code EPERM is returned. Signed-off-by: Dazhao Lao Reviewed-by: Ke Chen --- drivers/infiniband/hw/hns/hns_roce_device.h | 15 ++ drivers/infiniband/hw/hns/hns_roce_hw_v2.c | 48 ++++++ drivers/infiniband/hw/hns/hns_roce_hw_v2.h | 12 ++ drivers/infiniband/hw/hns/hns_roce_sysfs.c | 161 ++++++++++++++++++++ 4 files changed, 236 insertions(+) diff --git a/drivers/infiniband/hw/hns/hns_roce_device.h b/drivers/infiniband/hw/hns/hns_roce_device.h index c859c0e5c807..75ad7975322c 100644 --- a/drivers/infiniband/hw/hns/hns_roce_device.h +++ b/drivers/infiniband/hw/hns/hns_roce_device.h @@ -115,6 +115,8 @@ #define HNS_ROCE_MAX_CQ_COUNT 0xFFFF #define HNS_ROCE_MAX_CQ_PERIOD 0xFFFF +#define MAIN_PF_FUNC_ID 0 + enum { SERV_TYPE_RC, SERV_TYPE_UC, @@ -179,6 +181,10 @@ enum { HNS_ROCE_CAP_FLAG_POE = BIT(27), }; +enum { + FW_CAP_FLAG_CNP_PRI = BIT(3), +}; + #define HNS_ROCE_DB_TYPE_COUNT 2 #define HNS_ROCE_DB_UNIT_SIZE 4 @@ -1102,6 +1108,14 @@ struct hns_roce_hw { int (*query_scc_param)(struct hns_roce_dev *hr_dev, u8 port_num, enum hns_roce_scc_algo alog); int (*cfg_poe_ch)(struct hns_roce_dev *hr_dev, u32 index, u64 poe_addr); + int (*config_cnp_pri_param)(struct hns_roce_dev *hr_dev, u8 port_num); + int (*query_cnp_pri_param)(struct hns_roce_dev *hr_dev, u8 port_num); +}; + +struct hns_roce_cnp_pri_param { + __le32 param; + struct hns_roce_dev *hr_dev; + u8 port_num; }; #define HNS_ROCE_SCC_PARAM_SIZE 4 @@ -1120,6 +1134,7 @@ struct hns_roce_port { u8 port_num; struct kobject kobj; struct hns_roce_scc_param *scc_param; + struct hns_roce_cnp_pri_param *cnp_pri_param; }; struct hns_roce_mtr_node { diff --git a/drivers/infiniband/hw/hns/hns_roce_hw_v2.c b/drivers/infiniband/hw/hns/hns_roce_hw_v2.c index 0ddece06f505..e384d7118160 100644 --- a/drivers/infiniband/hw/hns/hns_roce_hw_v2.c +++ b/drivers/infiniband/hw/hns/hns_roce_hw_v2.c @@ -7376,6 +7376,52 @@ static enum hns_roce_opcode_type scc_opcode[] = { HNS_ROCE_OPC_CFG_DIP_PARAM, }; +static int hns_roce_v2_config_cnp_pri_param(struct hns_roce_dev *hr_dev, + u8 port_num) +{ + struct hns_roce_cnp_pri_param *cnp_pri_param; + struct hns_roce_cmq_desc desc; + struct hns_roce_port *pdata; + int ret; + + hns_roce_cmq_setup_basic_desc(&desc, HNS_ROCE_OPC_CFG_CNP_PRI, false); + pdata = &hr_dev->port_data[port_num - 1]; + cnp_pri_param = pdata->cnp_pri_param; + desc.data[0] = cnp_pri_param->param; + + ret = hns_roce_cmq_send(hr_dev, &desc, 1); + if (ret) + ibdev_err_ratelimited(&hr_dev->ib_dev, + "failed to configure cnp pri param, opcode: 0x%x, ret = %d.\n", + le16_to_cpu(desc.opcode), ret); + return ret; +} + + +static int hns_roce_v2_query_cnp_pri_param(struct hns_roce_dev *hr_dev, + u8 port_num) +{ + struct hns_roce_cnp_pri_param *cnp_pri_param; + struct hns_roce_cmq_desc desc; + struct hns_roce_port *pdata; + int ret; + + hns_roce_cmq_setup_basic_desc(&desc, HNS_ROCE_OPC_CFG_CNP_PRI, true); + ret = hns_roce_cmq_send(hr_dev, &desc, 1); + if (ret) { + ibdev_err_ratelimited(&hr_dev->ib_dev, + "failed to query cnp pri param, opcode: 0x%x, ret = %d.\n", + le16_to_cpu(desc.opcode), ret); + return ret; + } + + pdata = &hr_dev->port_data[port_num - 1]; + cnp_pri_param = pdata->cnp_pri_param; + cnp_pri_param->param = desc.data[0]; + + return 0; +} + static int hns_roce_v2_config_scc_param(struct hns_roce_dev *hr_dev, u8 port_num, enum hns_roce_scc_algo algo) @@ -7566,6 +7612,8 @@ static const struct hns_roce_hw hns_roce_hw_v2 = { .config_scc_param = hns_roce_v2_config_scc_param, .query_scc_param = hns_roce_v2_query_scc_param, .cfg_poe_ch = hns_roce_cfg_poe_ch, + .config_cnp_pri_param = hns_roce_v2_config_cnp_pri_param, + .query_cnp_pri_param = hns_roce_v2_query_cnp_pri_param, }; static const struct pci_device_id hns_roce_hw_v2_pci_tbl[] = { diff --git a/drivers/infiniband/hw/hns/hns_roce_hw_v2.h b/drivers/infiniband/hw/hns/hns_roce_hw_v2.h index 48c86b1a211c..b2ca6ae7fbc2 100644 --- a/drivers/infiniband/hw/hns/hns_roce_hw_v2.h +++ b/drivers/infiniband/hw/hns/hns_roce_hw_v2.h @@ -230,6 +230,7 @@ enum hns_roce_opcode_type { HNS_ROCE_OPC_CFG_GMV_BT = 0x8510, HNS_ROCE_OPC_SYNC_MB = 0x8511, HNS_ROCE_QUERY_RAM_ECC = 0x8513, + HNS_ROCE_OPC_CFG_CNP_PRI = 0x8514, HNS_SWITCH_PARAMETER_CFG = 0x1033, HNS_ROCE_OPC_SET_BOND_INFO = 0x8601, HNS_ROCE_OPC_CLEAR_BOND_INFO = 0x8602, @@ -1555,6 +1556,17 @@ struct hns_roce_wqe_atomic_seg { __le64 cmp_data; }; +#define HNS_ROCE_CNP_PRI_ENABLE_BIT_OFS 0 +#define HNS_ROCE_CNP_PRI_ENABLE_BIT_SZ 1 +#define HNS_ROCE_CNP_PRI_ENABLE_BIT_MASK GENMASK(0, 0) +#define HNS_ROCE_CNP_PRI_ENABLE_MAX 1 + +#define HNS_ROCE_CNP_PRI_DSCP_BIT_OFS (HNS_ROCE_CNP_PRI_ENABLE_BIT_OFS + \ + HNS_ROCE_CNP_PRI_ENABLE_BIT_SZ) +#define HNS_ROCE_CNP_PRI_DSCP_BIT_SZ 6 +#define HNS_ROCE_CNP_PRI_DSCP_BIT_MASK GENMASK(6, 1) +#define HNS_ROCE_CNP_PRI_DSCP_MAX 63 + #define HNS_ROCE_DCQCN_AI_OFS 0 #define HNS_ROCE_DCQCN_AI_SZ sizeof(u16) #define HNS_ROCE_DCQCN_AI_MAX ((u16)(~0U)) diff --git a/drivers/infiniband/hw/hns/hns_roce_sysfs.c b/drivers/infiniband/hw/hns/hns_roce_sysfs.c index 0262ec6716f1..2710f97e3af5 100644 --- a/drivers/infiniband/hw/hns/hns_roce_sysfs.c +++ b/drivers/infiniband/hw/hns/hns_roce_sysfs.c @@ -26,6 +26,41 @@ static void scc_param_config_work(struct work_struct *work) scc_param->algo_type); } +static void get_default_cnp_pri_param(struct hns_roce_dev *hr_dev, + struct hns_roce_port *pdata) +{ + if (hr_dev->is_vf || hr_dev->pci_dev->revision <= PCI_REVISION_ID_HIP09) + return; + + if (hr_dev->mac_type != HNAE3_MAC_ROH || + hr_dev->func_id != MAIN_PF_FUNC_ID) + return; + + if (!(hr_dev->caps.flags & HNS_ROCE_CAP_FLAG_QP_FLOW_CTRL) || + !(hr_dev->caps.fw_cap & FW_CAP_FLAG_CNP_PRI)) + return; + + hr_dev->hw->query_cnp_pri_param(hr_dev, pdata->port_num); +} + +static int alloc_cnp_pri_param(struct hns_roce_dev *hr_dev, + struct hns_roce_port *pdata) +{ + struct hns_roce_cnp_pri_param *cnp_pri_param; + + cnp_pri_param = kvzalloc(sizeof(*cnp_pri_param), GFP_KERNEL); + if (!cnp_pri_param) + return -ENOMEM; + + cnp_pri_param->hr_dev = hr_dev; + cnp_pri_param->port_num = pdata->port_num; + pdata->cnp_pri_param = cnp_pri_param; + + get_default_cnp_pri_param(hr_dev, pdata); + + return 0; +} + static void get_default_scc_param(struct hns_roce_dev *hr_dev, struct hns_roce_port *pdata) { @@ -77,6 +112,14 @@ struct hns_port_cc_attr { u32 min; }; +struct hns_port_cnp_pri_attr { + struct hns_port_attribute port_attr; + u32 bit_offset; + u32 bit_size; + u32 bit_mask; + u32 max; +}; + static int scc_attr_check(struct hns_port_cc_attr *scc_attr) { if (WARN_ON(scc_attr->size > sizeof(u32))) @@ -87,6 +130,63 @@ static int scc_attr_check(struct hns_port_cc_attr *scc_attr) return 0; } +static ssize_t cnp_pri_attr_show(struct hns_roce_port *pdata, + struct hns_port_attribute *attr, char *buf) +{ + struct hns_port_cnp_pri_attr *cnp_pri_attr = + container_of(attr, struct hns_port_cnp_pri_attr, port_attr); + struct hns_roce_cnp_pri_param *cnp_pri_param; + u32 param; + u32 val; + + cnp_pri_param = pdata->cnp_pri_param; + param = le32_to_cpu(cnp_pri_param->param); + val = (param & cnp_pri_attr->bit_mask) >> cnp_pri_attr->bit_offset; + + return sysfs_emit(buf, "%u\n", val); +} + +static ssize_t cnp_pri_attr_store(struct hns_roce_port *pdata, + struct hns_port_attribute *attr, + const char *buf, size_t count) +{ + struct hns_port_cnp_pri_attr *cnp_pri_attr = + container_of(attr, struct hns_port_cnp_pri_attr, port_attr); + struct hns_roce_cnp_pri_param *cnp_pri_param; + struct hns_roce_dev *hr_dev; + __le32 param_bak; + u32 param; + u32 val; + int ret; + + ret = kstrtou32(buf, 0, &val); + if (ret) + return ret; + + if (val > cnp_pri_attr->max) + return -EINVAL; + + cnp_pri_param = pdata->cnp_pri_param; + param = le32_to_cpu(cnp_pri_param->param); + if (cnp_pri_attr->bit_offset != HNS_ROCE_CNP_PRI_ENABLE_BIT_OFS && + !(param & HNS_ROCE_CNP_PRI_ENABLE_BIT_MASK)) + return -EPERM; + + param = param & (~cnp_pri_attr->bit_mask); + val = (val << cnp_pri_attr->bit_offset) | param; + param_bak = cnp_pri_param->param; + cnp_pri_param->param = cpu_to_le32(val); + hr_dev = cnp_pri_param->hr_dev; + + ret = hr_dev->hw->config_cnp_pri_param(hr_dev, cnp_pri_param->port_num); + if (ret) { + cnp_pri_param->param = param_bak; + return ret; + } + + return count; +} + static ssize_t scc_attr_show(struct hns_roce_port *pdata, struct hns_port_attribute *attr, char *buf) { @@ -151,6 +251,27 @@ static ssize_t scc_attr_store(struct hns_roce_port *pdata, return count; } +static umode_t cnp_pri_param_is_visible(struct kobject *kobj, + struct attribute *attr, int i) +{ + struct hns_roce_port *pdata = + container_of(kobj, struct hns_roce_port, kobj); + struct hns_roce_dev *hr_dev = pdata->hr_dev; + + if (hr_dev->is_vf || hr_dev->pci_dev->revision <= PCI_REVISION_ID_HIP09) + return 0; + + if (hr_dev->mac_type != HNAE3_MAC_ROH || + hr_dev->func_id != MAIN_PF_FUNC_ID) + return 0; + + if (!(hr_dev->caps.flags & HNS_ROCE_CAP_FLAG_QP_FLOW_CTRL) || + !(hr_dev->caps.fw_cap & FW_CAP_FLAG_CNP_PRI)) + return 0; + + return 0644; +} + static umode_t scc_attr_is_visible(struct kobject *kobj, struct attribute *attr, int i) { @@ -172,6 +293,37 @@ static umode_t scc_attr_is_visible(struct kobject *kobj, return 0644; } +#define __HNS_CNP_PRI_ATTR(_name, _offset, _size, _mask, _max) { \ + .port_attr = __ATTR(_name, 0644, cnp_pri_attr_show, cnp_pri_attr_store), \ + .bit_offset = _offset, \ + .bit_size = _size, \ + .bit_mask = _mask, \ + .max = _max, \ +} + +#define HNS_PORT_CNP_PRI_ATTR_RW(_name, NAME) \ + struct hns_port_cnp_pri_attr hns_roce_port_attr_cnp_pri_##_name = \ + __HNS_CNP_PRI_ATTR(_name, \ + HNS_ROCE_CNP_PRI_##NAME##_BIT_OFS, \ + HNS_ROCE_CNP_PRI_##NAME##_BIT_SZ, \ + HNS_ROCE_CNP_PRI_##NAME##_BIT_MASK, \ + HNS_ROCE_CNP_PRI_##NAME##_MAX) + +HNS_PORT_CNP_PRI_ATTR_RW(enable, ENABLE); +HNS_PORT_CNP_PRI_ATTR_RW(dscp, DSCP); + +static struct attribute *cnp_pri_param_attrs[] = { + &hns_roce_port_attr_cnp_pri_enable.port_attr.attr, + &hns_roce_port_attr_cnp_pri_dscp.port_attr.attr, + NULL, +}; + +static const struct attribute_group cnp_pri_param_group = { + .name = "cnp_pri_param", + .attrs = cnp_pri_param_attrs, + .is_visible = cnp_pri_param_is_visible, +}; + #define __HNS_SCC_ATTR(_name, _type, _offset, _size, _min, _max) { \ .port_attr = __ATTR(_name, 0644, scc_attr_show, scc_attr_store), \ .algo_type = _type, \ @@ -330,6 +482,7 @@ const struct attribute_group *hns_attr_port_groups[] = { &ldcp_cc_param_group, &hc3_cc_param_group, &dip_cc_param_group, + &cnp_pri_param_group, NULL, }; @@ -368,6 +521,7 @@ static void hns_roce_port_release(struct kobject *kobj) container_of(kobj, struct hns_roce_port, kobj); kfree(pdata->scc_param); + kvfree(pdata->cnp_pri_param); } static const struct sysfs_ops hns_roce_port_ops = { @@ -420,6 +574,13 @@ int hns_roce_create_port_files(struct ib_device *ibdev, u8 port_num, goto fail_group; } + ret = alloc_cnp_pri_param(hr_dev, pdata); + if (ret) { + dev_err(hr_dev->dev, "alloc cnp pri param failed, ret = %d!\n", + ret); + goto fail_group; + } + return ret; fail_group: -- Gitee From d0774b4990926e35e1811c03d3015c4e408549e6 Mon Sep 17 00:00:00 2001 From: Dazhao Lao Date: Tue, 20 Aug 2024 20:00:13 +0800 Subject: [PATCH 3/4] [PATCH OLK-5.10] Revert "RDMA/hns: Support RDMA_CM in ROH mode" driver inclusion category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/IAL7SX ---------------------------------------------------------------------- This reverts commit ac388b8ee07a431f9ade01dfdc49d02f75c4d160. Signed-off-by: Dazhao Lao Reviewed-by: Ke Chen --- drivers/infiniband/hw/hns/hns_roce_hw_v2.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/infiniband/hw/hns/hns_roce_hw_v2.c b/drivers/infiniband/hw/hns/hns_roce_hw_v2.c index e384d7118160..5207f42eb2b4 100644 --- a/drivers/infiniband/hw/hns/hns_roce_hw_v2.c +++ b/drivers/infiniband/hw/hns/hns_roce_hw_v2.c @@ -588,9 +588,6 @@ static inline int set_ud_wqe(struct hns_roce_qp *qp, if (ret) return ret; - if (hr_dev->mac_type == HNAE3_MAC_ROH && qp->ibqp.qp_type == IB_QPT_GSI) - ud_sq_wqe->dmac[0] = 0xFF; - qp->sl = to_hr_ah(ud_wr(wr)->ah)->av.sl; set_extend_sge(qp, wr->sg_list, &curr_idx, valid_num_sge); -- Gitee From b6b9d85b89d184fee5e67c6fde315a03c1cb51e0 Mon Sep 17 00:00:00 2001 From: Dazhao Lao Date: Tue, 20 Aug 2024 20:00:57 +0800 Subject: [PATCH 4/4] [PATCH OLK-5.10] RDMA/hns: Support getting GRH for UD in RoH mode when NLP = 0 driver inclusion category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/IAL7SX ---------------------------------------------------------------------- When NLP = 0 in RoH mode, IP was stripped out. This means that in UD, the receiving side cannot obtain routing information. This makes CM unusable. This patch builds GRH through SMAC so that CM can be used normally. This patch cannot solve the problem of using CM in all scenarios. There are the following constraints: 1. All IP addresses on the same port are required to have the same upper 8 bits; 2. Only support using the first non link-local GID for CM. Signed-off-by: Dazhao Lao Reviewed-by: Ke Chen --- drivers/infiniband/hw/hns/hns_roce_hw_v2.c | 97 +++++++++++++++++++++- drivers/infiniband/hw/hns/hns_roce_hw_v2.h | 3 +- 2 files changed, 98 insertions(+), 2 deletions(-) diff --git a/drivers/infiniband/hw/hns/hns_roce_hw_v2.c b/drivers/infiniband/hw/hns/hns_roce_hw_v2.c index 5207f42eb2b4..d75328515458 100644 --- a/drivers/infiniband/hw/hns/hns_roce_hw_v2.c +++ b/drivers/infiniband/hw/hns/hns_roce_hw_v2.c @@ -41,6 +41,7 @@ #include #include #include +#include #include "hnae3.h" #include "hclge_main.h" @@ -554,7 +555,6 @@ static inline int set_ud_wqe(struct hns_roce_qp *qp, void *wqe, unsigned int *sge_idx, unsigned int owner_bit) { - struct hns_roce_dev *hr_dev = to_hr_dev(qp->ibqp.device); struct hns_roce_ah *ah = to_hr_ah(ud_wr(wr)->ah); struct hns_roce_v2_ud_send_wqe *ud_sq_wqe = wqe; unsigned int curr_idx = *sge_idx; @@ -4395,6 +4395,100 @@ static int fill_recv_wc(struct ib_wc *wc, struct hns_roce_v2_cqe *cqe) return 0; } +struct ib_mad_list_head { + struct list_head list; + struct ib_cqe cqe; + struct ib_mad_queue *mad_queue; +}; + +struct ib_mad_private_header { + struct ib_mad_list_head mad_list; + struct ib_mad_recv_wc recv_wc; + struct ib_wc wc; + u64 mapping; +} __packed; + +struct ib_mad_private { + struct ib_mad_private_header header; + size_t mad_size; + struct ib_grh grh; + u8 mad[]; +} __packed; + +static inline struct ib_mad_list_head *to_mad_list_head(void *cqe) +{ + return container_of((struct ib_cqe *)cqe, struct ib_mad_list_head, cqe); +} + +static inline struct ib_mad_private_header + *to_mad_private_header(struct ib_mad_list_head *mad_list) +{ + return container_of(mad_list, struct ib_mad_private_header, mad_list); +} + +static inline struct ib_mad_private + *to_mad_private(struct ib_mad_private_header *header) +{ + return container_of(header, struct ib_mad_private, header); +} + +static bool find_first_in4_gid(struct hns_roce_dev *hr_dev, + struct hns_roce_qp *qp, union ib_gid *gid) +{ + int i; + + /* + * The performance of querying the gid table each time is not good, + * but if we want to cache the gid, we need to add a synchronization + * mechanism which will lead to an increase in software complexity. + * Considering that CM does not belong to the IO path and does not + * have high performance requirements, we use this simpler solution. + */ + for (i = 0; i < hr_dev->caps.gid_table_len[qp->port]; i += 1) { + if (rdma_query_gid(&hr_dev->ib_dev, qp->port + 1, i, gid)) + continue; + /* link local addr is not a valid in4 addr */ + if (rdma_link_local_addr((struct in6_addr *)gid->raw)) + continue; + + return true; + } + + return false; +} + +static void hns_roh_restore_grh(struct hns_roce_dev *hr_dev, + struct hns_roce_qp *qp, struct ib_wc *wc, + struct hns_roce_v2_cqe *cqe) +{ +#define IPV4_PREFIX_MASK 0xFF000000 + struct ib_mad_list_head *mad_list = to_mad_list_head((void *)wc->wr_id); + struct ib_mad_private_header *header = to_mad_private_header(mad_list); + struct ib_mad_private *mad_private = to_mad_private(header); + u32 smac = hr_reg_read(cqe, CQE_SMAC_L); + union rdma_network_hdr *hdr; + union ib_gid gid = {}; + u32 daddr; + + if (hr_dev->mac_type != HNAE3_MAC_ROH || qp->ibqp.qp_type != IB_QPT_GSI) + return; + + if (!find_first_in4_gid(hr_dev, qp, &gid)) + return; + + /* RoH only support IPv4, so interface_id won't bigger than U32_MAX */ + daddr = (u32)be64_to_cpu(gid.global.interface_id); + /* + * For RoH, only the lower 24 bit is valid, it needs to get the first + * 8 bit from the daddr + */ + smac = smac | (daddr & IPV4_PREFIX_MASK); + + hdr = (union rdma_network_hdr *)&mad_private->grh; + hdr->roce4grh.saddr = cpu_to_be32(smac); + hdr->roce4grh.daddr = cpu_to_be32(daddr); +} + static int hns_roce_v2_poll_one(struct hns_roce_cq *hr_cq, struct hns_roce_qp **cur_qp, struct ib_wc *wc) { @@ -4447,6 +4541,7 @@ static int hns_roce_v2_poll_one(struct hns_roce_cq *hr_cq, } else { wq = &qp->rq; wc->wr_id = wq->wrid[wq->tail & (wq->wqe_cnt - 1)]; + hns_roh_restore_grh(hr_dev, qp, wc, cqe); ++wq->tail; } diff --git a/drivers/infiniband/hw/hns/hns_roce_hw_v2.h b/drivers/infiniband/hw/hns/hns_roce_hw_v2.h index b2ca6ae7fbc2..de96d7fdcb24 100644 --- a/drivers/infiniband/hw/hns/hns_roce_hw_v2.h +++ b/drivers/infiniband/hw/hns/hns_roce_hw_v2.h @@ -737,7 +737,8 @@ struct hns_roce_v2_cqe { #define CQE_LCL_QPN CQE_FIELD_LOC(119, 96) #define CQE_SUB_STATUS CQE_FIELD_LOC(127, 120) #define CQE_BYTE_CNT CQE_FIELD_LOC(159, 128) -#define CQE_SMAC CQE_FIELD_LOC(207, 160) +#define CQE_SMAC_L CQE_FIELD_LOC(191, 160) +#define CQE_SMAC_H CQE_FIELD_LOC(207, 192) #define CQE_PORT_TYPE CQE_FIELD_LOC(209, 208) #define CQE_VID CQE_FIELD_LOC(221, 210) #define CQE_VID_VLD CQE_FIELD_LOC(222, 222) -- Gitee