Thread (21 messages) 21 messages, 4 authors, 2d ago

[PATCH 14/15] yunsilicon: add RDMA counters and sysfs

flat view
WARM2d

From: Xin Tian <hidden>
Date: 2026-10-12 11:45:13
Also in: linux-rdma, lkml
Subsystem: infiniband subsystem, the rest · Maintainers: Jason Gunthorpe, Leon Romanovsky, Linus Torvalds

Add the hardware counter reporting through the RDMA counter interface,
the global counter sysfs attributes and the hca_type/hw_rev sysfs
attributes.

Signed-off-by: Xin Tian <redacted>
---
 drivers/infiniband/hw/xsc/Makefile       |   3 +-
 drivers/infiniband/hw/xsc/counters.c     | 422 +++++++++++++++++++++++
 drivers/infiniband/hw/xsc/counters.h     |  31 ++
 drivers/infiniband/hw/xsc/main.c         |   4 +
 drivers/infiniband/hw/xsc/xsc_ib_sysfs.c |  64 ++++
 5 files changed, 523 insertions(+), 1 deletion(-)
 create mode 100644 drivers/infiniband/hw/xsc/counters.c
 create mode 100644 drivers/infiniband/hw/xsc/counters.h
 create mode 100644 drivers/infiniband/hw/xsc/xsc_ib_sysfs.c
diff --git a/drivers/infiniband/hw/xsc/Makefile b/drivers/infiniband/hw/xsc/Makefile
index d5ad0e573..48a6d2b0a 100644
--- a/drivers/infiniband/hw/xsc/Makefile
+++ b/drivers/infiniband/hw/xsc/Makefile
@@ -6,4 +6,5 @@ ccflags-y := -I$(srctree)/drivers/net/ethernet/yunsilicon/xsc
 
 obj-$(CONFIG_INFINIBAND_XSC) += xsc_ib.o
 
-xsc_ib-y := main.o cq.o qp.o mem.o mr.o srq.o ah.o
+xsc_ib-y := main.o cq.o qp.o mem.o mr.o ah.o counters.o \
+		xsc_ib_sysfs.o srq.o
diff --git a/drivers/infiniband/hw/xsc/counters.c b/drivers/infiniband/hw/xsc/counters.c
new file mode 100644
index 000000000..135df9595
--- /dev/null
+++ b/drivers/infiniband/hw/xsc/counters.c
@@ -0,0 +1,422 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2021 - 2026, Shanghai Yunsilicon Technology Co., Ltd.
+ * All rights reserved.
+ */
+
+#include <linux/sysfs.h>
+#include <linux/types.h>
+#include "common/xsc_core.h"
+#include "common/xsc_hsi.h"
+#include "common/driver.h"
+#include "common/xsc_cmd.h"
+#include "counters.h"
+#include "xsc_ib.h"
+
+#define COUNTERS_FILE_NAME         "counters"
+#define COUNTERS_NAMES_FILE_NAME   "counters_names"
+#define COUNTERS_VALUE_FILE_NAME   "counters_value"
+#define COUNTERS_ATTER_GROUP_NAME  "counters"
+#define GLOBAL_COUNTERS_GROUP_NAME "global_counters"
+#define GLOBAL_COUNTERS_FILE_NAME  "counters"
+
+static const struct counter_desc hw_rdma_stats_pf_desc[] = {
+	/*by mac port*/
+	{ XSC_DECLARE_STAT(struct xsc_hw_stats_rdma_pf,  rdma_tx_pkts) },//0
+	{ XSC_DECLARE_STAT(struct xsc_hw_stats_rdma_pf,  rdma_tx_bytes) },//1
+	{ XSC_DECLARE_STAT(struct xsc_hw_stats_rdma_pf,  rdma_rx_pkts) },//2
+	{ XSC_DECLARE_STAT(struct xsc_hw_stats_rdma_pf,  rdma_rx_bytes) },//3
+	{ XSC_DECLARE_STAT(struct xsc_hw_stats_rdma_pf,  np_cnp_sent) },//4
+	{ XSC_DECLARE_STAT(struct xsc_hw_stats_rdma_pf,  rp_cnp_handled) },//5
+	{ XSC_DECLARE_STAT(struct xsc_hw_stats_rdma_pf,  np_ecn_marked_roce_packets) },//6
+	{ XSC_DECLARE_STAT(struct xsc_hw_stats_rdma_pf,  rp_cnp_ignored) },//7
+	{ XSC_DECLARE_STAT(struct xsc_hw_stats_rdma_pf,  read_rsp_out_of_seq) },//8
+	{ XSC_DECLARE_STAT(struct xsc_hw_stats_rdma_pf,  implied_nak_seq_err) },//9
+	/*by function*/
+	{ XSC_DECLARE_STAT(struct xsc_hw_stats_rdma_pf,  out_of_sequence) },//10
+	{ XSC_DECLARE_STAT(struct xsc_hw_stats_rdma_pf,  packet_seq_err) },//11
+	{ XSC_DECLARE_STAT(struct xsc_hw_stats_rdma_pf,  out_of_buffer) },//12
+	{ XSC_DECLARE_STAT(struct xsc_hw_stats_rdma_pf,  rnr_nak_retry_err) },//13
+	{ XSC_DECLARE_STAT(struct xsc_hw_stats_rdma_pf,  local_ack_timeout_err) },//14
+	{ XSC_DECLARE_STAT(struct xsc_hw_stats_rdma_pf,  rx_read_requests) },//15
+	{ XSC_DECLARE_STAT(struct xsc_hw_stats_rdma_pf,  rx_write_requests) },//16
+	{ XSC_DECLARE_STAT(struct xsc_hw_stats_rdma_pf,  duplicate_requests) },//17
+	{ XSC_DECLARE_STAT(struct xsc_hw_stats_rdma_pf,  rdma_tx_pkts_func) },//18
+	{ XSC_DECLARE_STAT(struct xsc_hw_stats_rdma_pf,  rdma_tx_payload_bytes) },//19
+	{ XSC_DECLARE_STAT(struct xsc_hw_stats_rdma_pf,  rdma_rx_pkts_func) },//20
+	{ XSC_DECLARE_STAT(struct xsc_hw_stats_rdma_pf,  rdma_rx_payload_bytes) },//21
+	/*global*/
+	{ XSC_DECLARE_STAT(struct xsc_hw_stats_rdma_pf,  rdma_loopback_pkts) },//22
+	{ XSC_DECLARE_STAT(struct xsc_hw_stats_rdma_pf,  rdma_loopback_bytes) },//23
+	/*for diamond*/
+	{ XSC_DECLARE_STAT(struct xsc_hw_stats_rdma_pf,  out_of_sequence_sr) },//24
+	{ XSC_DECLARE_STAT(struct xsc_hw_stats_rdma_pf,  packet_seq_err_sr) },//25
+	{ XSC_DECLARE_STAT(struct xsc_hw_stats_rdma_pf,  rdma_ndp_rx_pkts) },//26
+	{ XSC_DECLARE_STAT(struct xsc_hw_stats_rdma_pf,  rdma_ndp_rx_trimmed_pkts) },//27
+	{ XSC_DECLARE_STAT(struct xsc_hw_stats_rdma_pf,  rdma_ndp_trimmed_pkts_sr) },//28
+	{ XSC_DECLARE_STAT(struct xsc_hw_stats_rdma_pf,  rx_icrc_encapsulated) },//29
+	/*XSC_CMDQ_GET_HW_STATS_RDMA_V1*/
+};
+
+static const struct counter_desc hw_rdma_stats_vf_desc[] = {
+	/*by function*/
+	{ XSC_DECLARE_STAT(struct xsc_hw_stats_rdma_vf,  rdma_tx_pkts_func) },
+	{ XSC_DECLARE_STAT(struct xsc_hw_stats_rdma_vf,  rdma_tx_payload_bytes) },
+	{ XSC_DECLARE_STAT(struct xsc_hw_stats_rdma_vf,  rdma_rx_pkts_func) },
+	{ XSC_DECLARE_STAT(struct xsc_hw_stats_rdma_vf,  rdma_rx_payload_bytes) },
+	{ XSC_DECLARE_STAT(struct xsc_hw_stats_rdma_vf,  out_of_sequence) },
+	{ XSC_DECLARE_STAT(struct xsc_hw_stats_rdma_vf,  packet_seq_err) },
+	{ XSC_DECLARE_STAT(struct xsc_hw_stats_rdma_vf,  out_of_buffer) },
+	{ XSC_DECLARE_STAT(struct xsc_hw_stats_rdma_vf,  rnr_nak_retry_err) },
+	{ XSC_DECLARE_STAT(struct xsc_hw_stats_rdma_vf,  local_ack_timeout_err) },
+	{ XSC_DECLARE_STAT(struct xsc_hw_stats_rdma_vf,  rx_read_requests) },
+	{ XSC_DECLARE_STAT(struct xsc_hw_stats_rdma_vf,  rx_write_requests) },
+	{ XSC_DECLARE_STAT(struct xsc_hw_stats_rdma_vf,  duplicate_requests) },
+};
+
+static const struct counter_desc hw_global_rdma_stats_desc[] = {
+	{ XSC_DECLARE_STAT(struct xsc_hw_global_stats_rdma,  rdma_loopback_pkts) },
+	{ XSC_DECLARE_STAT(struct xsc_hw_global_stats_rdma,  rdma_loopback_bytes) },
+	{ XSC_DECLARE_STAT(struct xsc_hw_global_stats_rdma,  rx_icrc_encapsulated) },
+	{ XSC_DECLARE_STAT(struct xsc_hw_global_stats_rdma,  req_cqe_error) },
+	{ XSC_DECLARE_STAT(struct xsc_hw_global_stats_rdma,  resp_cqe_error) },
+	{ XSC_DECLARE_STAT(struct xsc_hw_global_stats_rdma,  cqe_msg_code_error) },
+};
+
+static int get_hw_stats_rdma(struct xsc_core_device *dev, struct xsc_hw_stats_rdma *stats_rdma)
+{
+	int ret;
+	struct xsc_hw_stats_mbox_in in;
+	struct xsc_hw_stats_rdma_mbox_out out;
+
+	memset(stats_rdma, 0, sizeof(*stats_rdma));
+
+	if (!dev)
+		return -1;
+
+	memset(&in, 0, sizeof(in));
+	memset(&out, 0, sizeof(out));
+	in.mac_port = dev->mac_port;
+	in.hdr.ver = cpu_to_be16(XSC_CMDQ_GET_HW_STATS_RDMA_V1);
+	in.hdr.opcode = cpu_to_be16(XSC_CMD_OP_QUERY_HW_STATS_RDMA);
+
+	ret = xsc_cmd_exec(dev, (void *)&in, sizeof(in), (void *)&out, sizeof(out));
+	if (ret || out.hdr.status)
+		return -1;
+
+	memcpy(stats_rdma, &out.hw_stats, sizeof(*stats_rdma));
+
+	return 0;
+}
+
+static ssize_t counters_names_show(struct device *device,
+				   struct device_attribute *attr, char *buf)
+{
+	struct xsc_ib_dev *ibdev = container_of(device, struct xsc_ib_dev, ib_dev.dev);
+	struct xsc_core_device *xdev = ibdev->xdev;
+	struct xsc_hw_stats_rdma stats_rdma;
+	const struct counter_desc *desc;
+	int desc_size;
+	ssize_t count = 0;
+	u64 mask;
+	int i;
+
+	if (get_hw_stats_rdma(xdev, &stats_rdma))
+		return 0;
+
+	if (is_support_hw_pf_stats(xdev)) {
+		desc = hw_rdma_stats_pf_desc;
+		desc_size = ARRAY_SIZE(hw_rdma_stats_pf_desc);
+	} else {
+		desc = hw_rdma_stats_vf_desc;
+		desc_size = ARRAY_SIZE(hw_rdma_stats_vf_desc);
+	}
+
+	mask = xsc_get_rdma_stat_mask(xdev, be16_to_cpu(stats_rdma.ver));
+	for (i = 0; i < desc_size; i++) {
+		if (!((1ULL << i) & mask))
+			continue;
+		count += sysfs_emit_at(buf, count, "%s\n", desc[i].format);
+	}
+
+	return count;
+}
+static DEVICE_ATTR_RO(counters_names);
+
+static ssize_t counters_show(struct device *device,
+			     struct device_attribute *attr, char *buf)
+{
+	struct xsc_ib_dev *ibdev = container_of(device, struct xsc_ib_dev, ib_dev.dev);
+	struct xsc_core_device *xdev = ibdev->xdev;
+	struct xsc_hw_stats_rdma stats_rdma;
+	const struct counter_desc *desc;
+	int desc_size;
+	ssize_t count = 0;
+	u8 *stats;
+	u64 mask;
+	int i;
+
+	if (get_hw_stats_rdma(xdev, &stats_rdma) ||
+	    is_support_hw_pf_stats(xdev) != stats_rdma.is_pf)
+		return 0;
+
+	if (is_support_hw_pf_stats(xdev)) {
+		desc = hw_rdma_stats_pf_desc;
+		desc_size = ARRAY_SIZE(hw_rdma_stats_pf_desc);
+		stats = (u8 *)&stats_rdma.stats.pf_stats;
+	} else {
+		desc = hw_rdma_stats_vf_desc;
+		desc_size = ARRAY_SIZE(hw_rdma_stats_vf_desc);
+		stats = (u8 *)&stats_rdma.stats.vf_stats;
+	}
+
+	mask = xsc_get_rdma_stat_mask(xdev, be16_to_cpu(stats_rdma.ver));
+	for (i = 0; i < desc_size; i++) {
+		u64 value;
+
+		if (!((1ULL << i) & mask))
+			continue;
+		value = be64_to_cpu(*(u64 *)(stats + desc[i].offset));
+		count += sysfs_emit_at(buf, count, "%-26s    %-20llu\n",
+				       desc[i].format, value);
+	}
+
+	return count;
+}
+static DEVICE_ATTR_RO(counters);
+
+static ssize_t counters_value_read(struct file *file, struct kobject *kob,
+				   const struct bin_attribute *bin_attr,
+				   char *buf, loff_t loff, size_t size)
+{
+	struct xsc_ib_dev *ibdev = container_of(kob, struct xsc_ib_dev, ib_dev.dev.kobj);
+	struct xsc_core_device *xdev = ibdev->xdev;
+	struct xsc_hw_stats_rdma stats_rdma;
+	const struct counter_desc *desc;
+	int desc_size;
+	int bin_size;
+	u64 *tmp_value;
+	u8 *stats;
+	u64 mask;
+	int i, j;
+
+	if (bin_attr->size > size || bin_attr->size == 0)
+		return 0;
+
+	if (get_hw_stats_rdma(xdev, &stats_rdma) ||
+	    is_support_hw_pf_stats(xdev) != stats_rdma.is_pf)
+		return 0;
+
+	if (is_support_hw_pf_stats(xdev)) {
+		desc = hw_rdma_stats_pf_desc;
+		desc_size = ARRAY_SIZE(hw_rdma_stats_pf_desc);
+		stats = (u8 *)&stats_rdma.stats.pf_stats;
+	} else {
+		desc = hw_rdma_stats_vf_desc;
+		desc_size = ARRAY_SIZE(hw_rdma_stats_vf_desc);
+		stats = (u8 *)&stats_rdma.stats.vf_stats;
+	}
+
+	bin_size = desc_size * sizeof(u64);
+	if (bin_attr->size < bin_size)
+		return 0;
+
+	tmp_value = kzalloc(bin_attr->size, GFP_KERNEL);
+	if (!tmp_value)
+		return 0;
+
+	mask = xsc_get_rdma_stat_mask(xdev, be16_to_cpu(stats_rdma.ver));
+	j = 0;
+	for (i = 0; i < desc_size; i++) {
+		if (!((1ULL << i) & mask))
+			continue;
+		tmp_value[j] = be64_to_cpu(*(u64 *)(stats + desc[i].offset));
+		j++;
+	}
+
+	memcpy(buf, tmp_value, bin_attr->size);
+
+	kfree(tmp_value);
+	return bin_attr->size;
+}
+static BIN_ATTR_RO(counters_value, sizeof(struct xsc_hw_stats_rdma));
+
+static struct attribute *counters_attrs[] = {
+	&dev_attr_counters_names.attr,
+	&dev_attr_counters.attr,
+	NULL,
+};
+
+static const struct bin_attribute *const counters_bin_attrs[] = {
+	&bin_attr_counters_value,
+	NULL,
+};
+
+static const struct attribute_group counters_group = {
+	.name = "counters",
+	.attrs = counters_attrs,
+	.bin_attrs = counters_bin_attrs,
+};
+
+static int counters_sysfs_init(struct ib_device *ib_dev)
+{
+	return sysfs_create_group(&ib_dev->dev.kobj, &counters_group);
+}
+
+static void counters_sysfs_fini(struct ib_device *ib_dev)
+{
+	sysfs_remove_group(&ib_dev->dev.kobj, &counters_group);
+}
+
+static ssize_t global_cnt_attr_show(struct kobject *kobj,
+				    struct attribute *attr, char *buf)
+{
+	struct xsc_global_cnt_attributes *a =
+		container_of(attr, struct xsc_global_cnt_attributes, attr);
+	struct xsc_global_cnt_interface *g =
+		container_of(kobj, struct xsc_global_cnt_interface, kobj);
+
+	if (!a->show)
+		return -EIO;
+
+	return a->show(g, a, buf);
+}
+
+static ssize_t global_cnt_attr_store(struct kobject *kobj,
+				     struct attribute *attr,
+				     const char *buf, size_t size)
+{
+	struct xsc_global_cnt_attributes *a =
+		container_of(attr, struct xsc_global_cnt_attributes, attr);
+	struct xsc_global_cnt_interface *g =
+		container_of(kobj, struct xsc_global_cnt_interface, kobj);
+
+	if (!a->store)
+		return -EIO;
+
+	return a->store(g, a, buf, size);
+}
+
+static ssize_t global_counters_show(struct xsc_global_cnt_interface *g,
+				    struct xsc_global_cnt_attributes *a, char *buf)
+{
+	int i;
+	int ret;
+	u8 *stats;
+	u64 value;
+	int desc_size;
+	ssize_t count = 0;
+	const struct counter_desc *desc;
+	struct xsc_hw_global_stats_mbox_in in;
+	struct xsc_hw_global_stats_mbox_out out;
+
+	memset(&in, 0, sizeof(in));
+	memset(&out, 0, sizeof(out));
+	in.hdr.opcode = cpu_to_be16(XSC_CMD_OP_QUERY_HW_GLOBAL_STATS);
+	ret = xsc_cmd_exec(g->xdev, (void *)&in, sizeof(in),
+			   (void *)&out, sizeof(out));
+	if (ret || out.hdr.status)
+		return 0;
+
+	desc = &hw_global_rdma_stats_desc[0];
+	desc_size = ARRAY_SIZE(hw_global_rdma_stats_desc);
+	stats = (u8 *)&out.hw_stats;
+
+	for (i = 0 ; i < desc_size; i++) {
+		value = *(u64 *)(stats + desc[i].offset);
+		value = be64_to_cpu(value);
+		count += sprintf(&buf[count], "%-26s    %-20llu\n",
+				desc[i].format, value);
+	}
+
+	return count;
+}
+
+static ssize_t global_counters_store(struct xsc_global_cnt_interface *g,
+				     struct xsc_global_cnt_attributes *a,
+				     const char *buf, size_t count)
+{
+	return -EOPNOTSUPP;
+}
+
+#define GLOBAL_CNT_ATTR(_name) struct xsc_global_cnt_attributes xsc_global_cnt_attr_##_name = \
+	__ATTR(_name, 0444, global_##_name##_show, global_##_name##_store)
+
+GLOBAL_CNT_ATTR(counters);
+
+static const struct sysfs_ops global_cnt_sysfs_ops = {
+	.show = global_cnt_attr_show,
+	.store = global_cnt_attr_store,
+};
+
+static struct attribute *global_cnt_attrs[] = {
+	&xsc_global_cnt_attr_counters.attr,
+	NULL
+};
+
+ATTRIBUTE_GROUPS(global_cnt);
+
+static const struct kobj_type global_cnt_ktype = {
+	.sysfs_ops     = &global_cnt_sysfs_ops,
+	.default_groups = global_cnt_groups,
+};
+
+static struct xsc_global_cnt_interface *g_global_cnt_interface;
+
+static int global_cnt_sysfs_init(struct ib_device *ib_dev, struct xsc_core_device *xdev)
+{
+	struct xsc_global_cnt_interface *tmp;
+	int err;
+
+	if (!xdev || !xsc_core_is_pf(xdev) || xdev->pf_id != 0)
+		return 0;
+
+	tmp = kzalloc_obj(*tmp, GFP_KERNEL);
+	if (!tmp)
+		return -ENOMEM;
+
+	err = kobject_init_and_add(&tmp->kobj, &global_cnt_ktype,
+				   &ib_dev->dev.kobj, GLOBAL_COUNTERS_GROUP_NAME);
+	if (err)
+		goto error_return;
+
+	g_global_cnt_interface = tmp;
+	tmp->xdev = xdev;
+	return 0;
+
+error_return:
+	kobject_put(&tmp->kobj);
+	kfree(tmp);
+	return err;
+}
+
+static void global_cnt_sysfs_fini(struct xsc_core_device *xdev)
+{
+	if (!g_global_cnt_interface || !xdev || !xsc_core_is_pf(xdev) || xdev->pf_id != 0)
+		return;
+
+	kobject_put(&g_global_cnt_interface->kobj);
+	kfree(g_global_cnt_interface);
+	g_global_cnt_interface = NULL;
+}
+
+int xsc_counters_init(struct ib_device *ib_dev, struct xsc_core_device *xdev)
+{
+	int ret;
+
+	ret = counters_sysfs_init(ib_dev);
+	if (ret)
+		return ret;
+
+	ret = global_cnt_sysfs_init(ib_dev, xdev);
+	if (ret)
+		counters_sysfs_fini(ib_dev);
+
+	return ret;
+}
+
+void xsc_counters_fini(struct ib_device *ib_dev, struct xsc_core_device *xdev)
+{
+	counters_sysfs_fini(ib_dev);
+	global_cnt_sysfs_fini(xdev);
+}
diff --git a/drivers/infiniband/hw/xsc/counters.h b/drivers/infiniband/hw/xsc/counters.h
new file mode 100644
index 000000000..944dbafb6
--- /dev/null
+++ b/drivers/infiniband/hw/xsc/counters.h
@@ -0,0 +1,31 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2021 - 2026, Shanghai Yunsilicon Technology Co., Ltd.
+ * All rights reserved.
+ */
+
+#ifndef __COUNTERS_H__
+#define __COUNTERS_H__
+
+#define STRING_LEN		32
+#define XSC_DECLARE_STAT(type, fld)	""#fld, offsetof(type, fld)
+
+struct counter_desc {
+	char		format[STRING_LEN];
+	size_t		offset; /* Byte offset */
+};
+
+struct xsc_global_cnt_interface {
+	struct xsc_core_device  *xdev;
+	struct kobject		kobj;
+};
+
+struct xsc_global_cnt_attributes {
+	struct attribute attr;
+	ssize_t (*show)(struct xsc_global_cnt_interface *g, struct xsc_global_cnt_attributes *a,
+			char *buf);
+	ssize_t (*store)(struct xsc_global_cnt_interface *g, struct xsc_global_cnt_attributes *a,
+			 const char *buf, size_t count);
+};
+
+#endif
diff --git a/drivers/infiniband/hw/xsc/main.c b/drivers/infiniband/hw/xsc/main.c
index 30927006b..38c8b4f06 100644
--- a/drivers/infiniband/hw/xsc/main.c
+++ b/drivers/infiniband/hw/xsc/main.c
@@ -745,7 +745,9 @@ static int init_one(struct xsc_core_device *xdev,
 
 	xsc_register_netdev_notifier(dev);
 
+	xsc_counters_init(&dev->ib_dev, xdev);
 
+	xsc_ib_sysfs_init(&dev->ib_dev, xdev);
 
 	return 0;
 
@@ -759,6 +761,8 @@ static void remove_one(struct xsc_core_device *xdev, void *intf_ctx)
 {
 	struct xsc_ib_dev *dev = (struct xsc_ib_dev *)intf_ctx;
 
+	xsc_ib_sysfs_fini(&dev->ib_dev, xdev);
+	xsc_counters_fini(&dev->ib_dev, xdev);
 	xsc_unregister_netdev_notifier(dev);
 	ib_unregister_device(&dev->ib_dev);
 	ib_dealloc_device(&dev->ib_dev);
diff --git a/drivers/infiniband/hw/xsc/xsc_ib_sysfs.c b/drivers/infiniband/hw/xsc/xsc_ib_sysfs.c
new file mode 100644
index 000000000..a0b577bde
--- /dev/null
+++ b/drivers/infiniband/hw/xsc/xsc_ib_sysfs.c
@@ -0,0 +1,64 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2021 - 2026, Shanghai Yunsilicon Technology Co., Ltd.
+ * All rights reserved.
+ */
+
+#include <linux/sysfs.h>
+#include <linux/types.h>
+#include <linux/time.h>
+#include "common/xsc_core.h"
+#include "common/xsc_hsi.h"
+#include "common/driver.h"
+#include "common/xsc_cmd.h"
+#include "xsc_ib.h"
+
+static ssize_t hca_type_show(struct device *device, struct device_attribute *attr, char *buf)
+{
+	struct ib_device *ib_dev = container_of(device, struct ib_device, dev);
+	struct xsc_core_device *dev = to_xdev(ib_dev)->xdev;
+	struct pci_dev *pdev = dev->pdev;
+
+	return sprintf(buf, "%x\n", pdev->subsystem_device);
+}
+
+static DEVICE_ATTR_RO(hca_type);
+
+static ssize_t hw_rev_show(struct device *device, struct device_attribute *attr, char *buf)
+{
+	struct ib_device *ib_dev = container_of(device, struct ib_device, dev);
+	struct xsc_core_device *dev = to_xdev(ib_dev)->xdev;
+	u32 hw_ver = 0;
+
+	hw_ver = ((dev->chip_ver_l & 0xffff) << 16) |
+		(dev->hotfix_num & 0xffff);
+	return sprintf(buf, "0x%x\n", hw_ver);
+}
+
+static DEVICE_ATTR_RO(hw_rev);
+
+static struct device_attribute *xsc_ib_attributes[] = {
+	&dev_attr_hca_type,
+	&dev_attr_hw_rev,
+};
+
+void xsc_ib_sysfs_init(struct ib_device *ib_dev, struct xsc_core_device *xdev)
+{
+	int err = 0;
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(xsc_ib_attributes); i++) {
+		err = device_create_file(&ib_dev->dev, xsc_ib_attributes[i]);
+		if (err)
+			dev_err(&xdev->pdev->dev, "Create sysfs file for %s failed.\n",
+				xsc_ib_attributes[i]->attr.name);
+	}
+}
+
+void xsc_ib_sysfs_fini(struct ib_device *ib_dev, struct xsc_core_device *xdev)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(xsc_ib_attributes); i++)
+		device_remove_file(&ib_dev->dev, xsc_ib_attributes[i]);
+}
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help