[PATCH rdma v5 7/7] RDMA/zrdma: Implement device and port query operations

Yanze Zhang <[email protected]>
Newsgroups org.kernel.vger.linux-rdma,org.kernel.vger.linux-kernel
Message-ID <[email protected]>
Add implementation for querying device attributes, port attributes,
GID, PKey, and link layer information. Also include firmware
version string retrieval.

Signed-off-by: Yanze Zhang <[email protected]>
---
 drivers/infiniband/hw/zrdma/zrdma_verbs.c | 368 +++++++++++++++++++++-
 1 file changed, 355 insertions(+), 13 deletions(-)

diff --git a/drivers/infiniband/hw/zrdma/zrdma_verbs.c b/drivers/infiniband/hw/zrdma/zrdma_verbs.c
index 2194d34b6438..de691662922f 100644
--- a/drivers/infiniband/hw/zrdma/zrdma_verbs.c
+++ b/drivers/infiniband/hw/zrdma/zrdma_verbs.c
@@ -315,29 +315,303 @@ static int zxdh_mmap(struct ib_ucontext *context, struct vm_area_struct *vma)
 	return ret;
 }
 
-static void zxdh_init_roce_device(struct zxdh_device *zdev)
+static void extract_version(const char *input, char *output)
 {
-	zdev->ibdev.node_type = RDMA_NODE_IB_CA;
-	addrconf_addr_eui48((u8 *)&zdev->ibdev.node_guid,
-			    zdev->netdev->dev_addr);
+	const char *last_dash_pos = strrchr(input, '-');
+
+	if (last_dash_pos) {
+		const char *v_pos = strstr(last_dash_pos, "V");
+
+		if (v_pos)
+			strscpy(output, v_pos + 1, 12);
+		else
+			output[0] = '\0';
+	} else {
+		output[0] = '\0';
+	}
 }
 
-static int zxdh_init_rdma_device(struct zxdh_device *zdev)
+static int zxdh_query_device(struct ib_device *ibdev,
+			     struct ib_device_attr *props,
+			     struct ib_udata *udata)
 {
+	struct zxdh_device *zdev = to_zdev(ibdev);
 	struct pci_dev *pcidev = zdev->rf->pcidev;
+	int major, sub_major, minor, sub_minor;
+	struct net_device *slave = NULL;
+	struct ethtool_drvinfo info;
+	char extracted_version[16];
+	struct list_head *iter;
+
+	memset(&info, 0, sizeof(info));
+	if (zdev->netdev->priv_flags & IFF_BONDING) {
+		rcu_read_lock();
+		netdev_for_each_lower_dev(zdev->netdev, slave, iter) {
+			slave->ethtool_ops->get_drvinfo(slave, &info);
+			break;
+		}
+		rcu_read_unlock();
+		if (!slave) {
+			zdev->netdev->ethtool_ops->get_drvinfo(zdev->netdev,
+							       &info);
+		}
+	} else {
+		zdev->netdev->ethtool_ops->get_drvinfo(zdev->netdev, &info);
+	}
+	extract_version(info.fw_version, extracted_version);
+	if (sscanf(extracted_version, "%d.%d.%d.%d", &major, &sub_major, &minor,
+		   &sub_minor) != 4) {
+		major = 0;
+		sub_major = 0;
+		minor = 0;
+		sub_minor = 0;
+	}
 
-	if (zdev->roce_mode)
-		zxdh_init_roce_device(zdev);
+	if (udata->inlen || udata->outlen)
+		return -EINVAL;
+
+	memset(props, 0, sizeof(*props));
+	ether_addr_copy((u8 *)&props->sys_image_guid, zdev->netdev->dev_addr);
+	props->fw_ver = ((u64)major << 48 | (u64)sub_major << 32 |
+			 (u64)minor << 16 | sub_minor);
+	props->device_cap_flags =
+		IB_DEVICE_MEM_WINDOW | IB_DEVICE_MEM_MGT_EXTENSIONS |
+		IB_DEVICE_BAD_QKEY_CNTR | IB_DEVICE_SYS_IMAGE_GUID |
+		IB_DEVICE_RC_RNR_NAK_GEN | IB_DEVICE_N_NOTIFY_CQ;
+	props->vendor_id = pcidev->vendor;
+	props->vendor_part_id = pcidev->device;
+	props->hw_ver = pcidev->revision;
+	props->page_size_cap = SZ_4K | SZ_2M | SZ_1G;
+	props->max_mr_size = MAX_MR_SIZE;
+	props->max_qp = MAX_QP;
+	props->max_qp_wr = MAX_QP_WR;
+	props->max_cq = MAX_CQ;
+	props->max_cqe = MAX_CQE;
+	props->max_mr = MAX_MR;
+	props->max_mw = MAX_MW;
+	props->max_pd = MAX_PD;
+	props->max_sge_rd = MAX_SGE_RD;
+	props->max_qp_rd_atom = MAX_QP_RD_ATOM;
+	props->max_res_rd_atom = MAX_RES_RD_ATOM;
+	props->max_qp_init_rd_atom = MAX_QP_INIT_RD_ATOM;
+	props->max_srq = MAX_SRQ;
+	props->max_srq_wr = MAX_SRQ_WR;
+	props->max_srq_sge = MAX_SRQ_SGE;
+	props->local_ca_ack_delay = LOCAL_CA_ACK_DELAY;
+	props->hca_core_clock = HCA_CORE_CLOCK;
+	props->max_wq_type_rq = MAX_WQ_TYPE_RQ;
+	if (rdma_protocol_roce(ibdev, 1)) {
+		props->max_pkeys = ZXDH_PKEY_TBL_SZ;
+		props->max_ah = MAX_AH;
+		props->max_mcast_grp = 0;
+		props->max_mcast_qp_attach = 0;
+		props->max_total_mcast_qp_attach = 0;
+	}
+	props->max_fast_reg_page_list_len = MAX_FAST_REG_PAGE_LIST_LEN;
+	props->cq_caps.max_cq_moderation_count = MAX_CQ_MODERATION_COUNT;
+	props->cq_caps.max_cq_moderation_period = MAX_CQ_MODERATION_PERIOD;
+	props->timestamp_mask = TIMESTAMP_MASK;
+
+	return 0;
+}
+
+static u32 zxdh_get_eth_netdev_speed(struct zxdh_device *zdev, u32 port_num)
+{
+	struct ethtool_link_ksettings lksettings;
+	u32 netdev_speed = (u32)SPEED_UNKNOWN;
+	struct zxdh_pci_f *rf = zdev->rf;
+	int rc;
+
+	if (rdma_port_get_link_layer(&zdev->ibdev, port_num) !=
+	    IB_LINK_LAYER_ETHERNET)
+		return -EINVAL;
+
+	if (zdev->netdev_speed != (u32)SPEED_UNKNOWN)
+		return zdev->netdev_speed;
+
+	if (rf->drv_np_cap == ZXDH_RDMA_COMMON_FUNC_CAP &&
+	    rf->common_func_num_max > ZXDH_FUNC_NETDEV_SPEED_GET) {
+		rc = rf->gen_ops.zxdh_common_func(zdev->zxdh_adev->parent,
+						  &netdev_speed,
+						  ZXDH_FUNC_NETDEV_SPEED_GET);
+
+		if (rc || netdev_speed == (u32)SPEED_UNKNOWN)
+			netdev_speed = SPEED_1000;
+		else
+			zdev->netdev_speed = netdev_speed;
+	} else {
+		if (zdev->netdev_speed == (u32)SPEED_UNKNOWN) {
+			rtnl_lock();
+			rc = __ethtool_get_link_ksettings(zdev->netdev,
+							  &lksettings);
+			rtnl_unlock();
+
+			if (!rc &&
+			    lksettings.base.speed != (u32)SPEED_UNKNOWN) {
+				netdev_speed = lksettings.base.speed;
+				zdev->netdev_speed = netdev_speed;
+			} else {
+				netdev_speed = SPEED_1000;
+			}
+		} else {
+			netdev_speed = zdev->netdev_speed;
+		}
+	}
+
+	return netdev_speed;
+}
+
+static int zxdh_get_eth_speed(struct ib_device *dev, struct net_device *netdev,
+			      u32 port_num, u16 *speed, u8 *width)
+{
+	struct zxdh_device *zdev = to_zdev(dev);
+	u32 netdev_speed;
+
+	if (zdev)
+		netdev_speed = zxdh_get_eth_netdev_speed(zdev, port_num);
 	else
-		return -EPFNOSUPPORT;
+		netdev_speed = SPEED_1000;
+
+	if (netdev_speed <= SPEED_1000) {
+		*width = IB_WIDTH_1X;
+		*speed = IB_SPEED_SDR;
+	} else if (netdev_speed <= SPEED_10000) {
+		*width = IB_WIDTH_1X;
+		*speed = IB_SPEED_FDR10;
+	} else if (netdev_speed <= SPEED_20000) {
+		*width = IB_WIDTH_4X;
+		*speed = IB_SPEED_DDR;
+	} else if (netdev_speed <= SPEED_25000) {
+		*width = IB_WIDTH_1X;
+		*speed = IB_SPEED_EDR;
+	} else if (netdev_speed <= SPEED_40000) {
+		*width = IB_WIDTH_4X;
+		*speed = IB_SPEED_FDR10;
+	} else if (netdev_speed <= SPEED_100000) {
+		*width = IB_WIDTH_4X;
+		*speed = IB_SPEED_EDR;
+	} else {
+		*width = IB_WIDTH_4X;
+		*speed = IB_SPEED_HDR;
+	}
 
-	zdev->ibdev.phys_port_cnt = 1;
-	zdev->ibdev.num_comp_vectors = zdev->rf->ceqs_count;
-	zdev->ibdev.dev.parent = &pcidev->dev;
+	return 0;
+}
+
+static int zxdh_query_port(struct ib_device *ibdev, u32 port,
+			   struct ib_port_attr *props)
+{
+	struct zxdh_device *zdev = to_zdev(ibdev);
+	struct net_device *netdev = zdev->netdev;
+
+	props->max_mtu = IB_MTU_4096;
+	props->active_mtu = zxdh_mtu_int_to_enum(netdev->mtu);
+	props->lid = 0;
+	props->lmc = 0;
+	props->sm_lid = 0;
+	props->sm_sl = 0;
+	if (netif_carrier_ok(netdev) && netif_running(netdev)) {
+		props->state = IB_PORT_ACTIVE;
+		props->phys_state = IB_PORT_PHYS_STATE_LINK_UP;
+	} else {
+		props->state = IB_PORT_DOWN;
+		props->phys_state = IB_PORT_PHYS_STATE_DISABLED;
+	}
+	zxdh_get_eth_speed(ibdev, netdev, port, &props->active_speed,
+			   &props->active_width);
+	if (rdma_protocol_roce(ibdev, 1)) {
+		props->gid_tbl_len = 255;
+		props->ip_gids = true;
+		props->pkey_tbl_len = ZXDH_PKEY_TBL_SZ;
+	} else {
+		props->gid_tbl_len = 1;
+	}
+	props->port_cap_flags |= IB_PORT_CM_SUP;
+	props->max_msg_sz = MAX_MSG_SZ;
+	props->qkey_viol_cntr = 0;
+
+	return 0;
+}
+
+static enum rdma_link_layer zxdh_get_link_layer(struct ib_device *ibdev,
+						u32 port_num)
+{
+	return IB_LINK_LAYER_ETHERNET;
+}
+
+static int zxdh_query_pkey(struct ib_device *ibdev, u32 port, u16 index,
+			   u16 *pkey)
+{
+	if (index >= ZXDH_PKEY_TBL_SZ)
+		return -EINVAL;
+
+	*pkey = ZXDH_DEFAULT_PKEY;
+	return 0;
+}
+
+static int zxdh_query_gid_roce(struct ib_device *ibdev, u32 port, int index,
+			       union ib_gid *gid)
+{
+	int ret;
+
+	ret = rdma_query_gid(ibdev, port, index, gid);
+	if (ret == -EAGAIN) {
+		memcpy(gid, &zgid, sizeof(*gid));
+		return 0;
+	}
+
+	return ret;
+}
+
+static int zxdh_roce_port_immutable(struct ib_device *ibdev, u32 port_num,
+				    struct ib_port_immutable *immutable)
+{
+	struct ib_port_attr attr;
+	int err;
+
+	immutable->core_cap_flags = RDMA_CORE_PORT_IBA_ROCE_UDP_ENCAP |
+				    RDMA_CORE_CAP_PROT_ROCE;
+	err = ib_query_port(ibdev, port_num, &attr);
+	if (err)
+		return err;
+
+	immutable->max_mad_size = IB_MGMT_MAD_SIZE;
+	immutable->pkey_tbl_len = attr.pkey_tbl_len;
+	immutable->gid_tbl_len = attr.gid_tbl_len;
 
 	return 0;
 }
 
+static void zxdh_get_dev_fw_str(struct ib_device *dev, char *str)
+{
+	struct zxdh_device *zdev = to_zdev(dev);
+	struct net_device *slave = NULL;
+	struct ethtool_drvinfo info;
+	char extracted_version[16];
+	struct list_head *iter;
+
+	memset(&info, 0, sizeof(info));
+
+	if (zdev->netdev->priv_flags & IFF_BONDING) {
+		rcu_read_lock();
+		netdev_for_each_lower_dev(zdev->netdev, slave, iter) {
+			slave->ethtool_ops->get_drvinfo(slave, &info);
+			break;
+		}
+		rcu_read_unlock();
+		if (!slave) {
+			zdev->netdev->ethtool_ops->get_drvinfo(zdev->netdev,
+							       &info);
+		}
+		extract_version(info.fw_version, extracted_version);
+		snprintf(str, IB_FW_VERSION_NAME_MAX, "%s", extracted_version);
+		return;
+	}
+	zdev->netdev->ethtool_ops->get_drvinfo(zdev->netdev, &info);
+	extract_version(info.fw_version, extracted_version);
+	snprintf(str, IB_FW_VERSION_NAME_MAX, "%s", extracted_version);
+}
+
 static const struct ib_device_ops zxdh_dev_ops = {
 	.owner = THIS_MODULE,
 	.driver_id = RDMA_DRIVER_ZRDMA,
@@ -347,6 +621,13 @@ static const struct ib_device_ops zxdh_dev_ops = {
 	.dealloc_driver = zxdh_ib_dealloc_device,
 	.dealloc_pd = zxdh_dealloc_pd,
 	.dealloc_ucontext = zxdh_dealloc_ucontext,
+	.query_device = zxdh_query_device,
+	.query_port = zxdh_query_port,
+	.query_gid = zxdh_query_gid_roce,
+	.query_pkey = zxdh_query_pkey,
+	.get_link_layer = zxdh_get_link_layer,
+	.get_port_immutable = zxdh_roce_port_immutable,
+	.get_dev_fw_str = zxdh_get_dev_fw_str,
 	.mmap = zxdh_mmap,
 	.mmap_free = zxdh_mmap_free,
 
@@ -354,17 +635,78 @@ static const struct ib_device_ops zxdh_dev_ops = {
 	INIT_RDMA_OBJ_SIZE(ib_ucontext, zxdh_ucontext, ibucontext),
 };
 
+static void zxdh_init_roce_device(struct zxdh_device *zdev)
+{
+	zdev->ibdev.node_type = RDMA_NODE_IB_CA;
+	addrconf_addr_eui48((u8 *)&zdev->ibdev.node_guid,
+			    zdev->netdev->dev_addr);
+}
+
+static int zxdh_init_rdma_device(struct zxdh_device *zdev)
+{
+	struct pci_dev *pcidev = zdev->rf->pcidev;
+
+	if (zdev->roce_mode)
+		zxdh_init_roce_device(zdev);
+	else
+		return -EPFNOSUPPORT;
+
+	zdev->ibdev.phys_port_cnt = 1;
+	zdev->ibdev.num_comp_vectors = zdev->rf->ceqs_count;
+	zdev->ibdev.dev.parent = &pcidev->dev;
+
+	ib_set_device_ops(&zdev->ibdev, &zxdh_dev_ops);
+
+	return 0;
+}
+
+static void zxdh_port_ibevent(struct zxdh_device *zdev)
+{
+	struct ib_event event;
+
+	event.device = &zdev->ibdev;
+	event.element.port_num = 1;
+	event.event = zdev->ibdev_status ? IB_EVENT_PORT_ACTIVE :
+						 IB_EVENT_PORT_ERR;
+	ib_dispatch_event(&event);
+}
+
 int zxdh_ib_register_device(struct zxdh_device *zdev)
 {
+	char name[IB_DEVICE_NAME_MAX] = {};
 	int ret;
+	int err;
 
 	ret = zxdh_init_rdma_device(zdev);
 	if (ret)
 		return ret;
 
-	ib_set_device_ops(&zdev->ibdev, &zxdh_dev_ops);
+	ret = zxdh_get_del_rdma_name(pci_name(zdev->rf->pcidev), name);
+	if (ret)
+		snprintf(name, IB_DEVICE_NAME_MAX, "%s", "zrdma%d");
+
+	ret = ib_device_set_netdev(&zdev->ibdev, zdev->netdev, 1);
+	if (ret)
+		goto error;
+
+	zdev->rf->hw.device = &zdev->rf->pcidev->dev;
+	dma_set_max_seg_size(zdev->rf->hw.device, SZ_1G);
 
-	ret = ib_register_device(&zdev->ibdev, "zrdma%d", zdev->rf->hw.device);
+	ret = ib_register_device(&zdev->ibdev, name, zdev->rf->hw.device);
+	if (ret) {
+		snprintf(name, IB_DEVICE_NAME_MAX, "%s", "zrdma%d");
+		err = ib_register_device(&zdev->ibdev, name,
+					 zdev->rf->hw.device);
+		if (err)
+			goto error;
+	}
+
+	zdev->ibdev_status = 1;
+	zxdh_port_ibevent(zdev);
+
+	return 0;
+
+error:
 	if (ret)
 		pr_err("zrdma: Register RDMA device fail\n");
 
-- 
2.27.0
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.