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

366 lines
11 KiB
C

// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (C) 2021 - 2023, Shanghai Yunsilicon Technology Co., Ltd.
* All rights reserved.
*/
#include <linux/fs.h>
#include "common/xsc_core.h"
#include "common/xsc_hsi.h"
#include "common/driver.h"
#include "common/xsc_lag.h"
#include "common/xsc_cmd.h"
#include "counters.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"
static const struct counter_desc hw_stats_desc[] = {
/*by mac port*/
{ XSC_DECLARE_STAT(struct xsc_hw_stats, rdma_tx_pkts) },
{ XSC_DECLARE_STAT(struct xsc_hw_stats, rdma_tx_bytes) },
{ XSC_DECLARE_STAT(struct xsc_hw_stats, rdma_rx_pkts) },
{ XSC_DECLARE_STAT(struct xsc_hw_stats, rdma_rx_bytes) },
{ XSC_DECLARE_STAT(struct xsc_hw_stats, np_cnp_sent) },
{ XSC_DECLARE_STAT(struct xsc_hw_stats, rp_cnp_handled) },
{ XSC_DECLARE_STAT(struct xsc_hw_stats, np_ecn_marked_roce_packets) },
{ XSC_DECLARE_STAT(struct xsc_hw_stats, rp_cnp_ignored) },
{ XSC_DECLARE_STAT(struct xsc_hw_stats, tx_pause) },
{ XSC_DECLARE_STAT(struct xsc_hw_stats, rx_pause) },
{ XSC_DECLARE_STAT(struct xsc_hw_stats, rx_fcs_errors) },
{ XSC_DECLARE_STAT(struct xsc_hw_stats, rx_discards) },
/*by function*/
{ XSC_DECLARE_STAT(struct xsc_hw_stats, out_of_sequence) },
{ XSC_DECLARE_STAT(struct xsc_hw_stats, packet_seq_err) },
{ XSC_DECLARE_STAT(struct xsc_hw_stats, out_of_buffer) },
{ XSC_DECLARE_STAT(struct xsc_hw_stats, rnr_nak_retry_err) },
{ XSC_DECLARE_STAT(struct xsc_hw_stats, local_ack_timeout_err) },
{ XSC_DECLARE_STAT(struct xsc_hw_stats, rx_read_requests) },
{ XSC_DECLARE_STAT(struct xsc_hw_stats, rx_write_requests) },
{ XSC_DECLARE_STAT(struct xsc_hw_stats, duplicate_requests) },
{ XSC_DECLARE_STAT(struct xsc_hw_stats, rdma_tx_pkts_func) },
{ XSC_DECLARE_STAT(struct xsc_hw_stats, rdma_tx_payload_bytes) },
{ XSC_DECLARE_STAT(struct xsc_hw_stats, rdma_rx_pkts_func) },
{ XSC_DECLARE_STAT(struct xsc_hw_stats, rdma_rx_payload_bytes) },
/*by global*/
{ XSC_DECLARE_STAT(struct xsc_hw_stats, rdma_loopback_pkts) },
{ XSC_DECLARE_STAT(struct xsc_hw_stats, rdma_loopback_bytes) },
};
static const struct counter_desc vf_hw_stats_desc[] = {
/*by function*/
{ XSC_DECLARE_STAT(struct xsc_hw_stats, out_of_sequence) },
{ XSC_DECLARE_STAT(struct xsc_hw_stats, packet_seq_err) },
{ XSC_DECLARE_STAT(struct xsc_hw_stats, out_of_buffer) },
{ XSC_DECLARE_STAT(struct xsc_hw_stats, rnr_nak_retry_err) },
{ XSC_DECLARE_STAT(struct xsc_hw_stats, local_ack_timeout_err) },
{ XSC_DECLARE_STAT(struct xsc_hw_stats, rx_read_requests) },
{ XSC_DECLARE_STAT(struct xsc_hw_stats, rx_write_requests) },
{ XSC_DECLARE_STAT(struct xsc_hw_stats, duplicate_requests) },
{ XSC_DECLARE_STAT(struct xsc_hw_stats, rdma_tx_pkts_func) },
{ XSC_DECLARE_STAT(struct xsc_hw_stats, rdma_tx_payload_bytes) },
{ XSC_DECLARE_STAT(struct xsc_hw_stats, rdma_rx_pkts_func) },
{ XSC_DECLARE_STAT(struct xsc_hw_stats, rdma_rx_payload_bytes) },
};
static ssize_t counters_names_show(struct kobject *kobjs,
struct attribute *attr, char *buf)
{
int i;
ssize_t count = 0;
struct xsc_counters_attribute *xsc_counters_name_attr;
const struct counter_desc *desc;
xsc_counters_name_attr = container_of(attr,
struct xsc_counters_attribute,
attr);
if (!xsc_counters_name_attr->dev ||
!xsc_counters_name_attr->desc ||
xsc_counters_name_attr->desc_size == 0)
return 0;
for (i = 0; i < xsc_counters_name_attr->desc_size; ++i) {
desc = xsc_counters_name_attr->desc + i;
count += sprintf(&buf[count], "%s\n", desc->format);
}
return count;
}
static ssize_t counters_show(struct kobject *kobjs,
struct attribute *attr, char *buf)
{
int i;
ssize_t count = 0;
struct xsc_counters_attribute *xsc_counters_attr;
struct xsc_hw_stats_mbox_in *in;
struct xsc_hw_stats_mbox_out out;
struct xsc_core_device *dev;
int ret;
u64 counter;
const struct counter_desc *desc;
int inlen;
struct xsc_lag *ldev;
xsc_counters_attr = container_of(attr,
struct xsc_counters_attribute,
attr);
if (!xsc_counters_attr->dev ||
!xsc_counters_attr->desc ||
xsc_counters_attr->desc_size == 0)
return 0;
dev = xsc_counters_attr->dev;
ldev = xsc_lag_dev_get(dev);
if (ldev && __xsc_lag_is_roce(ldev))
inlen = sizeof(struct xsc_hw_stats_mbox_in) + XSC_MAX_PORTS;
else
inlen = sizeof(struct xsc_hw_stats_mbox_in);
in = kzalloc(inlen, GFP_KERNEL);
if (!in)
return 0;
memset(&out, 0, sizeof(out));
in->hdr.opcode = cpu_to_be16(XSC_CMD_OP_QUERY_HW_STATS);
if (ldev && __xsc_lag_is_roce(ldev)) {
in->is_lag = 1;
in->lag_member_num = XSC_MAX_PORTS;
for (i = 0; i < XSC_MAX_PORTS; i++)
in->member_port[i] = ldev->pf[i].xdev->mac_port;
} else {
in->is_lag = 0;
in->mac_port = dev->mac_port;
}
ret = xsc_cmd_exec(dev, (void *)in, inlen, (void *)&out, sizeof(out));
if (ret || out.hdr.status) {
kfree(in);
return 0;
}
for (i = 0 ; i < xsc_counters_attr->desc_size; ++i) {
desc = xsc_counters_attr->desc + i;
counter = *(u64 *)((char *)&out.hw_stats + desc->offset);
counter = be64_to_cpu(counter);
count += sprintf(&buf[count], "%-26s %-20llu\n",
desc->format, counter);
}
kfree(in);
return count;
}
static ssize_t counters_value_read(struct file *file,
struct kobject *kob,
struct bin_attribute *bin_attr,
char *buf, loff_t loff, size_t size)
{
int i;
struct xsc_counters_bin_attribute *xsc_counters_bin_attr;
u64 *tmp_value;
struct xsc_hw_stats_mbox_in in;
struct xsc_hw_stats_mbox_out out;
struct xsc_core_device *dev;
int ret;
const struct counter_desc *desc;
xsc_counters_bin_attr = container_of(&bin_attr->attr,
struct xsc_counters_bin_attribute,
attr);
if (!xsc_counters_bin_attr->dev ||
!xsc_counters_bin_attr->desc ||
xsc_counters_bin_attr->desc_size == 0 ||
xsc_counters_bin_attr->size == 0)
return 0;
dev = xsc_counters_bin_attr->dev;
memset(&in, 0, sizeof(in));
memset(&out, 0, sizeof(out));
in.hdr.opcode = cpu_to_be16(XSC_CMD_OP_QUERY_HW_STATS);
in.mac_port = dev->mac_port;
ret = xsc_cmd_exec(dev, (void *)&in, sizeof(in), (void *)&out, sizeof(out));
if (ret || out.hdr.status)
return 0;
tmp_value = kmalloc(xsc_counters_bin_attr->size, GFP_KERNEL);
if (!tmp_value)
return 0;
for (i = 0; i < xsc_counters_bin_attr->desc_size; ++i) {
desc = xsc_counters_bin_attr->desc + i;
tmp_value[i] = *(u64 *)((char *)&out.hw_stats + desc->offset);
tmp_value[i] = be64_to_cpu(tmp_value[i]);
}
memcpy(buf, tmp_value, xsc_counters_bin_attr->size);
kfree(tmp_value);
return xsc_counters_bin_attr->size;
}
int xsc_counters_init(struct ib_device *ib_dev, struct xsc_core_device *dev)
{
struct xsc_counters_attribute *xsc_counters_name, *xsc_counters;
struct xsc_counters_bin_attribute *xsc_counters_bin;
struct attribute_group *counters_attr_g;
struct bin_attribute **counters_bin_attrs;
struct attribute **counters_attrs;
int id, is_pf;
int ret = -ENOMEM;
xsc_counters_name = kzalloc(sizeof(*xsc_counters_name), GFP_KERNEL);
if (!xsc_counters_name)
return -ENOMEM;
xsc_counters = kzalloc(sizeof(*xsc_counters), GFP_KERNEL);
if (!xsc_counters)
goto err_xsc_counters;
xsc_counters_bin = kzalloc(sizeof(*xsc_counters_bin), GFP_KERNEL);
if (!xsc_counters_bin)
goto err_xsc_counters_bin;
id = dev->mac_port;
is_pf = xsc_core_is_pf(dev);
xsc_core_dbg(dev, "get xscale id = %d, is_pf = %d.\n", id, is_pf);
counters_bin_attrs = kzalloc(sizeof(*counters_bin_attrs) * 2, GFP_KERNEL);
if (!counters_bin_attrs)
goto err_counters_bin_attrs;
counters_attrs = kzalloc(sizeof(*counters_attrs) * 3, GFP_KERNEL);
if (!counters_attrs)
goto err_counters_attrs;
counters_attr_g = kzalloc(sizeof(*counters_attr_g), GFP_KERNEL);
if (!counters_attr_g)
goto err_counters_attr_g;
sysfs_attr_init(&xsc_counters_name->attr);
xsc_counters_name->attr.name = COUNTERS_NAMES_FILE_NAME;
xsc_counters_name->attr.mode = 0444;
xsc_counters_name->show = counters_names_show;
sysfs_attr_init(&xsc_counters->attr);
xsc_counters->attr.name = COUNTERS_FILE_NAME;
xsc_counters->attr.mode = 0444;
xsc_counters->show = counters_show;
xsc_counters->id = id;
xsc_counters->dev = dev;
sysfs_attr_init(&xsc_counters_bin->attr);
xsc_counters_bin->attr.name = COUNTERS_VALUE_FILE_NAME;
xsc_counters_bin->attr.mode = 0444;
xsc_counters_bin->read = counters_value_read;
xsc_counters_bin->id = id;
xsc_counters_bin->dev = dev;
if (is_pf) {
xsc_counters_name->desc = &hw_stats_desc[0];
xsc_counters->desc = &hw_stats_desc[0];
xsc_counters_bin->desc = &hw_stats_desc[0];
xsc_counters_name->desc_size = ARRAY_SIZE(hw_stats_desc);
xsc_counters->desc_size = ARRAY_SIZE(hw_stats_desc);
xsc_counters_bin->desc_size = ARRAY_SIZE(hw_stats_desc);
xsc_counters_bin->size = xsc_counters_bin->desc_size * sizeof(u64);
} else {
xsc_counters_name->desc = &vf_hw_stats_desc[0];
xsc_counters->desc = &vf_hw_stats_desc[0];
xsc_counters_bin->desc = &vf_hw_stats_desc[0];
xsc_counters_name->desc_size = ARRAY_SIZE(vf_hw_stats_desc);
xsc_counters->desc_size = ARRAY_SIZE(vf_hw_stats_desc);
xsc_counters_bin->desc_size = ARRAY_SIZE(vf_hw_stats_desc);
xsc_counters_bin->size = xsc_counters_bin->desc_size * sizeof(u64);
}
counters_bin_attrs[0] = (struct bin_attribute *)xsc_counters_bin;
counters_attrs[0] = (struct attribute *)xsc_counters_name;
counters_attrs[1] = (struct attribute *)xsc_counters;
counters_attr_g->name = COUNTERS_ATTER_GROUP_NAME;
counters_attr_g->attrs = counters_attrs;
counters_attr_g->bin_attrs = counters_bin_attrs;
dev->counters_priv = counters_attr_g;
ret = sysfs_create_group(&ib_dev->dev.kobj, counters_attr_g);
if (ret)
goto err_counters_create_group;
return 0;
err_counters_create_group:
kfree(counters_attr_g);
counters_attr_g = NULL;
err_counters_attr_g:
kfree(counters_attrs);
counters_attrs = NULL;
err_counters_attrs:
kfree(counters_bin_attrs);
counters_bin_attrs = NULL;
err_counters_bin_attrs:
kfree(xsc_counters_bin);
xsc_counters_bin = NULL;
err_xsc_counters_bin:
kfree(xsc_counters);
xsc_counters = NULL;
err_xsc_counters:
kfree(xsc_counters_name);
xsc_counters_name = NULL;
return ret;
}
void xsc_counters_fini(struct ib_device *ib_dev, struct xsc_core_device *dev)
{
struct xsc_counters_attribute *xsc_counters_name, *xsc_counters;
struct xsc_counters_bin_attribute *xsc_counters_bin;
struct bin_attribute **counters_bin_attrs;
struct attribute **counters_attrs;
struct attribute_group *counters_attr_g;
counters_attr_g = dev->counters_priv;
counters_attrs = counters_attr_g->attrs;
counters_bin_attrs = counters_attr_g->bin_attrs;
xsc_counters_bin = (struct xsc_counters_bin_attribute *)counters_bin_attrs[0];
xsc_counters_name = (struct xsc_counters_attribute *)counters_attrs[0];
xsc_counters = (struct xsc_counters_attribute *)counters_attrs[1];
if (counters_attr_g) {
sysfs_remove_group(&ib_dev->dev.kobj, counters_attr_g);
kfree(counters_attr_g);
counters_attr_g = NULL;
}
kfree(counters_attrs);
counters_attrs = NULL;
kfree(counters_bin_attrs);
counters_bin_attrs = NULL;
kfree(xsc_counters_bin);
xsc_counters_bin = NULL;
kfree(xsc_counters_name);
xsc_counters_name = NULL;
kfree(xsc_counters);
xsc_counters = NULL;
xsc_core_dbg(dev, "ok\n");
}