2026-01-29 22:25:33 +08:00

412 lines
11 KiB
C

// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (C) 2021 - 2023, 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"
struct xsc_rtt_interface {
struct xsc_core_device *xdev;
struct kobject kobj;
};
struct xsc_rtt_attributes {
struct attribute attr;
ssize_t (*show)(struct xsc_rtt_interface *g, struct xsc_rtt_attributes *a,
char *buf);
ssize_t (*store)(struct xsc_rtt_interface *g, struct xsc_rtt_attributes *a,
const char *buf, size_t count);
};
static ssize_t enable_show(struct xsc_rtt_interface *g, struct xsc_rtt_attributes *a,
char *buf)
{
int err;
struct xsc_inbox_hdr in;
struct xsc_rtt_en_mbox_out out;
memset(&in, 0, sizeof(in));
memset(&out, 0, sizeof(out));
in.opcode = __cpu_to_be16(XSC_CMD_OP_GET_RTT_EN);
err = xsc_cmd_exec(g->xdev, (void *)&in, sizeof(struct xsc_inbox_hdr),
(void *)&out, sizeof(struct xsc_rtt_en_mbox_out));
if (err || out.hdr.status) {
xsc_core_err(g->xdev, "Failed to get rtt en, err(%u), status(%u)\n",
err, out.hdr.status);
return -EINVAL;
}
return sprintf(buf, "%u\n", out.en);
}
static ssize_t enable_store(struct xsc_rtt_interface *g, struct xsc_rtt_attributes *a,
const char *buf, size_t count)
{
int err;
u16 rtt_enable;
struct xsc_rtt_en_mbox_in in;
struct xsc_rtt_en_mbox_out out;
err = kstrtou16(buf, 0, &rtt_enable);
if (err != 0)
return -EINVAL;
if (rtt_enable > 1) {
xsc_core_err(g->xdev, "Failed to set rtt en, rtt_enable(%u) out of range[0,1]\n",
rtt_enable);
return -EINVAL;
}
memset(&in, 0, sizeof(in));
memset(&out, 0, sizeof(out));
in.hdr.opcode = __cpu_to_be16(XSC_CMD_OP_SET_RTT_EN);
in.en = rtt_enable;
err = xsc_cmd_exec(g->xdev, (void *)&in, sizeof(struct xsc_rtt_en_mbox_in),
(void *)&out, sizeof(struct xsc_rtt_en_mbox_out));
if (err || out.hdr.status) {
xsc_core_err(g->xdev, "Failed to set rtt en, err(%u), status(%u)\n",
err, out.hdr.status);
return -EINVAL;
}
return count;
}
static ssize_t qpn_show(struct xsc_rtt_interface *g, struct xsc_rtt_attributes *a,
char *buf)
{
int err, i;
u32 count = 0;
struct xsc_inbox_hdr in;
struct xsc_get_rtt_qpn_mbox_out out;
memset(&in, 0, sizeof(in));
memset(&out, 0, sizeof(out));
in.opcode = __cpu_to_be16(XSC_CMD_OP_GET_RTT_QPN);
err = xsc_cmd_exec(g->xdev, (void *)&in, sizeof(struct xsc_inbox_hdr),
(void *)&out, sizeof(struct xsc_get_rtt_qpn_mbox_out));
if (err || out.hdr.status) {
xsc_core_err(g->xdev, "Failed to get rtt qpn, err(%u), status(%u)\n",
err, out.hdr.status);
return -EINVAL;
}
for (i = 0; i < (XSC_RTT_CFG_QPN_MAX - 1); i++)
count += sprintf(&buf[count], "%hu,", __be16_to_cpu(out.qpn[i]));
count += sprintf(&buf[count], "%hu\n", __be16_to_cpu(out.qpn[i]));
return count;
}
#define RTT_CFG_QPN_FORMAT "%hu,%hu,%hu,%hu,%hu,%hu,%hu,%hu,%hu,%hu,%hu,%hu,%hu," \
"%hu,%hu,%hu,%hu,%hu,%hu,%hu,%hu,%hu,%hu,%hu,%hu,%hu,%hu,%hu,%hu,%hu,%hu,%hu"
static ssize_t qpn_store(struct xsc_rtt_interface *g, struct xsc_rtt_attributes *a,
const char *buf, size_t count)
{
int err, i;
struct xsc_rtt_qpn_mbox_in in;
struct xsc_rtt_qpn_mbox_out out;
u16 *ptr = in.qpn;
memset(&in, 0, sizeof(in));
memset(&out, 0, sizeof(out));
err = sscanf(buf, RTT_CFG_QPN_FORMAT, &ptr[0], &ptr[1], &ptr[2], &ptr[3], &ptr[4],
&ptr[5], &ptr[6], &ptr[7], &ptr[8], &ptr[9], &ptr[10], &ptr[11], &ptr[12],
&ptr[13], &ptr[14], &ptr[15], &ptr[16], &ptr[17], &ptr[18], &ptr[19],
&ptr[20], &ptr[21], &ptr[22], &ptr[23], &ptr[24], &ptr[25], &ptr[26],
&ptr[27], &ptr[28], &ptr[29], &ptr[30], &ptr[31]);
if (err != XSC_RTT_CFG_QPN_MAX)
return -EINVAL;
in.hdr.opcode = __cpu_to_be16(XSC_CMD_OP_SET_RTT_QPN);
for (i = 0 ; i < XSC_RTT_CFG_QPN_MAX; i++)
in.qpn[i] = __cpu_to_be16(ptr[i]);
err = xsc_cmd_exec(g->xdev, (void *)&in, sizeof(struct xsc_rtt_qpn_mbox_in),
(void *)&out, sizeof(struct xsc_rtt_qpn_mbox_out));
if (err || out.hdr.status) {
xsc_core_err(g->xdev, "Failed to set rtt qpn, err(%u), status(%u)\n",
err, out.hdr.status);
return -EINVAL;
}
return count;
}
static ssize_t period_show(struct xsc_rtt_interface *g, struct xsc_rtt_attributes *a,
char *buf)
{
int err;
struct xsc_inbox_hdr in;
struct xsc_rtt_period_mbox_out out;
memset(&in, 0, sizeof(in));
memset(&out, 0, sizeof(out));
in.opcode = __cpu_to_be16(XSC_CMD_OP_GET_RTT_PERIOD);
err = xsc_cmd_exec(g->xdev, (void *)&in, sizeof(struct xsc_inbox_hdr),
(void *)&out, sizeof(struct xsc_rtt_period_mbox_out));
if (err || out.hdr.status) {
xsc_core_err(g->xdev, "Failed to get rtt period, err(%u), status(%u)\n",
err, out.hdr.status);
return -EINVAL;
}
return sprintf(buf, "%u\n", __be32_to_cpu(out.period));
}
#define RTT_CFG_PERIOD_MAX 10000 //ms, 10s
static ssize_t period_store(struct xsc_rtt_interface *g, struct xsc_rtt_attributes *a,
const char *buf, size_t count)
{
int err;
u32 rtt_period;
struct xsc_rtt_period_mbox_in in;
struct xsc_rtt_period_mbox_out out;
err = kstrtouint(buf, 0, &rtt_period);
if (err != 0)
return -EINVAL;
if (rtt_period > RTT_CFG_PERIOD_MAX)
return -EINVAL;
memset(&in, 0, sizeof(in));
memset(&out, 0, sizeof(out));
in.hdr.opcode = __cpu_to_be16(XSC_CMD_OP_SET_RTT_PERIOD);
in.period = __cpu_to_be32(rtt_period);
err = xsc_cmd_exec(g->xdev, (void *)&in, sizeof(struct xsc_rtt_period_mbox_in),
(void *)&out, sizeof(struct xsc_rtt_period_mbox_out));
if (err || out.hdr.status) {
xsc_core_err(g->xdev, "Failed to set rtt period, err(%u), status(%u)\n",
err, out.hdr.status);
return -EINVAL;
}
return count;
}
static ssize_t result_show(struct xsc_rtt_interface *g, struct xsc_rtt_attributes *a,
char *buf)
{
int i, err;
u32 count = 0;
struct xsc_inbox_hdr in;
struct xsc_rtt_result_mbox_out out;
memset(&in, 0, sizeof(in));
memset(&out, 0, sizeof(out));
in.opcode = __cpu_to_be16(XSC_CMD_OP_GET_RTT_RESULT);
err = xsc_cmd_exec(g->xdev, (void *)&in, sizeof(struct xsc_inbox_hdr),
(void *)&out, sizeof(struct xsc_rtt_result_mbox_out));
if (err || out.hdr.status) {
xsc_core_err(g->xdev, "Failed to get rtt result, err(%u), status(%u)\n",
err, out.hdr.status);
return -EINVAL;
}
for (i = 0; i < (XSC_RTT_CFG_QPN_MAX - 1); i++)
count += sprintf(&buf[count], "%lld,", __be64_to_cpu(out.result[i]));
count += sprintf(&buf[count], "%lld\n", __be64_to_cpu(out.result[i]));
return count;
}
static ssize_t result_store(struct xsc_rtt_interface *g, struct xsc_rtt_attributes *a,
const char *buf, size_t count)
{
return -EOPNOTSUPP;
}
static ssize_t stats_show(struct xsc_rtt_interface *g, struct xsc_rtt_attributes *a,
char *buf)
{
int err;
u32 count = 0;
struct xsc_inbox_hdr in;
struct xsc_rtt_stats_mbox_out out;
memset(&in, 0, sizeof(in));
memset(&out, 0, sizeof(out));
in.opcode = __cpu_to_be16(XSC_CMD_OP_GET_RTT_STATS);
err = xsc_cmd_exec(g->xdev, (void *)&in, sizeof(struct xsc_inbox_hdr),
(void *)&out, sizeof(struct xsc_rtt_stats_mbox_out));
if (err || out.hdr.status) {
xsc_core_err(g->xdev, "Failed to get rtt stats, err(%u), status(%u)\n",
err, out.hdr.status);
return -EINVAL;
}
count += sprintf(&buf[count], "rtt_succ_snd_req_cnt %llu\n",
__be64_to_cpu(out.stats.rtt_succ_snd_req_cnt));
count += sprintf(&buf[count], "rtt_succ_snd_rsp_cnt %llu\n",
__be64_to_cpu(out.stats.rtt_succ_snd_rsp_cnt));
count += sprintf(&buf[count], "rtt_fail_snd_req_cnt %llu\n",
__be64_to_cpu(out.stats.rtt_fail_snd_req_cnt));
count += sprintf(&buf[count], "rtt_fail_snd_rsp_cnt %llu\n",
__be64_to_cpu(out.stats.rtt_fail_snd_rsp_cnt));
count += sprintf(&buf[count], "rtt_rcv_req_cnt %llu\n",
__be64_to_cpu(out.stats.rtt_rcv_req_cnt));
count += sprintf(&buf[count], "rtt_rcv_rsp_cnt %llu\n",
__be64_to_cpu(out.stats.rtt_rcv_rsp_cnt));
count += sprintf(&buf[count], "rtt_rcv_unk_cnt %llu\n",
__be64_to_cpu(out.stats.rtt_rcv_unk_cnt));
count += sprintf(&buf[count], "rtt_grp_invalid_cnt %llu\n",
__be64_to_cpu(out.stats.rtt_grp_invalid_cnt));
return count;
}
static ssize_t stats_store(struct xsc_rtt_interface *g, struct xsc_rtt_attributes *a,
const char *buf, size_t count)
{
return -EOPNOTSUPP;
}
#define RTT_ATTR(_name) struct xsc_rtt_attributes xsc_rtt_attr_##_name = \
__ATTR(rtt_probe_##_name, 0644, _name##_show, _name##_store)
RTT_ATTR(enable);
RTT_ATTR(qpn);
RTT_ATTR(period);
RTT_ATTR(result);
RTT_ATTR(stats);
static ssize_t rtt_attr_show(struct kobject *kobj,
struct attribute *attr, char *buf)
{
struct xsc_rtt_attributes *ga =
container_of(attr, struct xsc_rtt_attributes, attr);
struct xsc_rtt_interface *g = container_of(kobj, struct xsc_rtt_interface, kobj);
if (!ga->show)
return -EIO;
return ga->show(g, ga, buf);
}
static ssize_t rtt_attr_store(struct kobject *kobj,
struct attribute *attr,
const char *buf, size_t size)
{
struct xsc_rtt_attributes *ga =
container_of(attr, struct xsc_rtt_attributes, attr);
struct xsc_rtt_interface *g = container_of(kobj, struct xsc_rtt_interface, kobj);
if (!ga->store)
return -EIO;
return ga->store(g, ga, buf, size);
}
static const struct sysfs_ops rtt_sysfs_ops = {
.show = rtt_attr_show,
.store = rtt_attr_store,
};
static struct attribute *rtt_attrs[] = {
&xsc_rtt_attr_enable.attr,
&xsc_rtt_attr_qpn.attr,
&xsc_rtt_attr_period.attr,
&xsc_rtt_attr_result.attr,
&xsc_rtt_attr_stats.attr,
NULL
};
ATTRIBUTE_GROUPS(rtt);
static const struct kobj_type rtt_ktype = {
.sysfs_ops = &rtt_sysfs_ops,
.default_groups = rtt_groups,
};
int xsc_rtt_sysfs_init(struct ib_device *ib_dev, struct xsc_core_device *xdev)
{
struct xsc_rtt_interface *tmp;
int err;
if (!xdev || !xsc_core_is_pf(xdev) || xdev->pf_id != 0)
return -EACCES;
tmp = kzalloc(sizeof(*tmp), GFP_KERNEL);
if (!tmp)
return -ENOMEM;
err = kobject_init_and_add(&tmp->kobj, &rtt_ktype,
&ib_dev->dev.kobj, "rtt");
if (err)
goto rtt_attr_err;
xdev->rtt_priv = tmp;
tmp->xdev = xdev;
return 0;
rtt_attr_err:
kobject_put(&tmp->kobj);
kfree(tmp);
return err;
}
void xsc_rtt_sysfs_fini(struct xsc_core_device *xdev)
{
int err;
struct xsc_rtt_en_mbox_in in;
struct xsc_rtt_en_mbox_out out;
struct xsc_rtt_period_mbox_in period_in;
struct xsc_rtt_period_mbox_out period_out;
struct xsc_rtt_interface *rtt;
if (!xdev || !xdev->rtt_priv)
return;
memset(&in, 0, sizeof(in));
memset(&out, 0, sizeof(out));
in.hdr.opcode = __cpu_to_be16(XSC_CMD_OP_SET_RTT_EN);
in.en = 0;
err = xsc_cmd_exec(xdev, (void *)&in, sizeof(struct xsc_rtt_en_mbox_in),
(void *)&out, sizeof(struct xsc_rtt_en_mbox_out));
if (err || out.hdr.status)
xsc_core_err(xdev, "Failed to set rtt disable, err(%u), status(%u)\n",
err, out.hdr.status);
memset(&period_in, 0, sizeof(period_in));
memset(&period_out, 0, sizeof(period_out));
period_in.hdr.opcode = __cpu_to_be16(XSC_CMD_OP_SET_RTT_PERIOD);
period_in.period = __cpu_to_be32(RTT_CFG_PERIOD_MAX);
err = xsc_cmd_exec(xdev, (void *)&period_in, sizeof(struct xsc_rtt_period_mbox_in),
(void *)&period_out, sizeof(struct xsc_rtt_period_mbox_out));
if (err || period_out.hdr.status)
xsc_core_err(xdev, "Failed to set rtt period default, err(%u), status(%u)\n",
err, out.hdr.status);
rtt = xdev->rtt_priv;
kobject_put(&rtt->kobj);
kfree(rtt);
xdev->rtt_priv = NULL;
}