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

347 lines
9.9 KiB
C

// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
/*
* Copyright (c) 2023 Hisilicon Limited.
*/
#include <rdma/ib_sysfs.h>
#include "hnae3.h"
#include "hns_roce_device.h"
#include "hns_roce_hw_v2.h"
static void scc_param_config_work(struct work_struct *work)
{
struct hns_roce_scc_param *scc_param = container_of(work,
struct hns_roce_scc_param, scc_cfg_dwork.work);
struct hns_roce_dev *hr_dev = scc_param->hr_dev;
hr_dev->hw->config_scc_param(hr_dev, scc_param->algo_type);
}
static void get_default_scc_param(struct hns_roce_dev *hr_dev)
{
int ret;
int i;
for (i = 0; i < HNS_ROCE_SCC_ALGO_TOTAL; i++) {
hr_dev->scc_param[i].timestamp = jiffies;
ret = hr_dev->hw->query_scc_param(hr_dev, i);
if (ret && ret != -EOPNOTSUPP)
ibdev_warn_ratelimited(&hr_dev->ib_dev,
"failed to get default parameters of scc algo %d, ret = %d.\n",
i, ret);
}
}
int hns_roce_alloc_scc_param(struct hns_roce_dev *hr_dev)
{
struct hns_roce_scc_param *scc_param;
int i;
scc_param = kvcalloc(HNS_ROCE_SCC_ALGO_TOTAL, sizeof(*scc_param),
GFP_KERNEL);
if (!scc_param)
return -ENOMEM;
for (i = 0; i < HNS_ROCE_SCC_ALGO_TOTAL; i++) {
scc_param[i].algo_type = i;
scc_param[i].hr_dev = hr_dev;
INIT_DELAYED_WORK(&scc_param[i].scc_cfg_dwork,
scc_param_config_work);
}
hr_dev->scc_param = scc_param;
get_default_scc_param(hr_dev);
return 0;
}
void hns_roce_dealloc_scc_param(struct hns_roce_dev *hr_dev)
{
int i;
if (!hr_dev->scc_param)
return;
for (i = 0; i < HNS_ROCE_SCC_ALGO_TOTAL; i++)
cancel_delayed_work_sync(&hr_dev->scc_param[i].scc_cfg_dwork);
kvfree(hr_dev->scc_param);
hr_dev->scc_param = NULL;
}
struct hns_port_cc_attr {
struct ib_port_attribute port_attr;
enum hns_roce_scc_algo algo_type;
u32 offset;
u32 size;
u32 max;
u32 min;
};
static int scc_attr_check(struct hns_roce_dev *hr_dev,
struct hns_port_cc_attr *scc_attr, u32 port_num)
{
if (port_num > hr_dev->caps.num_ports)
return -ENODEV;
if (WARN_ON(scc_attr->size > sizeof(u32)))
return -EINVAL;
if (WARN_ON(scc_attr->algo_type >= HNS_ROCE_SCC_ALGO_TOTAL))
return -EINVAL;
return 0;
}
static ssize_t scc_attr_show(struct ib_device *ibdev, u32 port_num,
struct ib_port_attribute *attr, char *buf)
{
struct hns_port_cc_attr *scc_attr =
container_of(attr, struct hns_port_cc_attr, port_attr);
struct hns_roce_dev *hr_dev = to_hr_dev(ibdev);
struct hns_roce_scc_param *scc_param;
__le32 val = 0;
int ret;
ret = scc_attr_check(hr_dev, scc_attr, port_num);
if (ret)
return ret;
scc_param = &hr_dev->scc_param[scc_attr->algo_type];
memcpy(&val, (void *)scc_param + scc_attr->offset, scc_attr->size);
return sysfs_emit(buf, "%u\n", le32_to_cpu(val));
}
static ssize_t scc_attr_store(struct ib_device *ibdev, u32 port_num,
struct ib_port_attribute *attr, const char *buf,
size_t count)
{
struct hns_port_cc_attr *scc_attr =
container_of(attr, struct hns_port_cc_attr, port_attr);
struct hns_roce_dev *hr_dev = to_hr_dev(ibdev);
struct hns_roce_scc_param *scc_param;
unsigned long lifespan_jiffies;
unsigned long exp_time;
__le32 attr_val;
u32 val;
int ret;
ret = scc_attr_check(hr_dev, scc_attr, port_num);
if (ret)
return ret;
if (kstrtou32(buf, 0, &val))
return -EINVAL;
if (val > scc_attr->max || val < scc_attr->min)
return -EINVAL;
attr_val = cpu_to_le32(val);
scc_param = &hr_dev->scc_param[scc_attr->algo_type];
memcpy((void *)scc_param + scc_attr->offset, &attr_val,
scc_attr->size);
/* lifespan is only used for driver */
if (scc_attr->offset >= offsetof(typeof(*scc_param), lifespan))
return count;
lifespan_jiffies = msecs_to_jiffies(scc_param->lifespan);
exp_time = scc_param->timestamp + lifespan_jiffies;
if (time_is_before_eq_jiffies(exp_time)) {
scc_param->timestamp = jiffies;
queue_delayed_work(hr_dev->irq_workq, &scc_param->scc_cfg_dwork,
lifespan_jiffies);
}
return count;
}
static umode_t scc_attr_is_visible(struct kobject *kobj,
struct attribute *attr, int i)
{
struct ib_port_attribute *port_attr =
container_of(attr, struct ib_port_attribute, attr);
struct hns_port_cc_attr *scc_attr =
container_of(port_attr, struct hns_port_cc_attr, port_attr);
u32 port_num;
struct ib_device *ibdev = ib_port_sysfs_get_ibdev_kobj(kobj, &port_num);
struct hns_roce_dev *hr_dev = to_hr_dev(ibdev);
if (!hr_dev->scc_param)
return 0;
if (hr_dev->is_vf ||
!(hr_dev->caps.flags & HNS_ROCE_CAP_FLAG_QP_FLOW_CTRL))
return 0;
if (!(hr_dev->caps.cong_cap & (1 << scc_attr->algo_type)))
return 0;
return 0644;
}
#define __HNS_SCC_ATTR(_name, _type, _offset, _size, _min, _max) { \
.port_attr = __ATTR(_name, 0644, scc_attr_show, scc_attr_store), \
.algo_type = _type, \
.offset = _offset, \
.size = _size, \
.min = _min, \
.max = _max, \
}
#define HNS_PORT_DCQCN_CC_ATTR_RW(_name, NAME) \
struct hns_port_cc_attr hns_roce_port_attr_dcqcn_##_name = \
__HNS_SCC_ATTR(_name, HNS_ROCE_SCC_ALGO_DCQCN, \
HNS_ROCE_DCQCN_##NAME##_OFS, \
HNS_ROCE_DCQCN_##NAME##_SZ, \
0, HNS_ROCE_DCQCN_##NAME##_MAX)
HNS_PORT_DCQCN_CC_ATTR_RW(ai, AI);
HNS_PORT_DCQCN_CC_ATTR_RW(f, F);
HNS_PORT_DCQCN_CC_ATTR_RW(tkp, TKP);
HNS_PORT_DCQCN_CC_ATTR_RW(tmp, TMP);
HNS_PORT_DCQCN_CC_ATTR_RW(alp, ALP);
HNS_PORT_DCQCN_CC_ATTR_RW(max_speed, MAX_SPEED);
HNS_PORT_DCQCN_CC_ATTR_RW(g, G);
HNS_PORT_DCQCN_CC_ATTR_RW(al, AL);
HNS_PORT_DCQCN_CC_ATTR_RW(cnp_time, CNP_TIME);
HNS_PORT_DCQCN_CC_ATTR_RW(ashift, ASHIFT);
HNS_PORT_DCQCN_CC_ATTR_RW(lifespan, LIFESPAN);
static struct attribute *dcqcn_param_attrs[] = {
&hns_roce_port_attr_dcqcn_ai.port_attr.attr,
&hns_roce_port_attr_dcqcn_f.port_attr.attr,
&hns_roce_port_attr_dcqcn_tkp.port_attr.attr,
&hns_roce_port_attr_dcqcn_tmp.port_attr.attr,
&hns_roce_port_attr_dcqcn_alp.port_attr.attr,
&hns_roce_port_attr_dcqcn_max_speed.port_attr.attr,
&hns_roce_port_attr_dcqcn_g.port_attr.attr,
&hns_roce_port_attr_dcqcn_al.port_attr.attr,
&hns_roce_port_attr_dcqcn_cnp_time.port_attr.attr,
&hns_roce_port_attr_dcqcn_ashift.port_attr.attr,
&hns_roce_port_attr_dcqcn_lifespan.port_attr.attr,
NULL,
};
static const struct attribute_group dcqcn_cc_param_group = {
.name = "dcqcn_cc_param",
.attrs = dcqcn_param_attrs,
.is_visible = scc_attr_is_visible,
};
#define HNS_PORT_LDCP_CC_ATTR_RW(_name, NAME) \
struct hns_port_cc_attr hns_roce_port_attr_ldcp_##_name = \
__HNS_SCC_ATTR(_name, HNS_ROCE_SCC_ALGO_LDCP, \
HNS_ROCE_LDCP_##NAME##_OFS, \
HNS_ROCE_LDCP_##NAME##_SZ, \
0, HNS_ROCE_LDCP_##NAME##_MAX)
HNS_PORT_LDCP_CC_ATTR_RW(cwd0, CWD0);
HNS_PORT_LDCP_CC_ATTR_RW(alpha, ALPHA);
HNS_PORT_LDCP_CC_ATTR_RW(gamma, GAMMA);
HNS_PORT_LDCP_CC_ATTR_RW(beta, BETA);
HNS_PORT_LDCP_CC_ATTR_RW(eta, ETA);
HNS_PORT_LDCP_CC_ATTR_RW(lifespan, LIFESPAN);
static struct attribute *ldcp_param_attrs[] = {
&hns_roce_port_attr_ldcp_cwd0.port_attr.attr,
&hns_roce_port_attr_ldcp_alpha.port_attr.attr,
&hns_roce_port_attr_ldcp_gamma.port_attr.attr,
&hns_roce_port_attr_ldcp_beta.port_attr.attr,
&hns_roce_port_attr_ldcp_eta.port_attr.attr,
&hns_roce_port_attr_ldcp_lifespan.port_attr.attr,
NULL,
};
static const struct attribute_group ldcp_cc_param_group = {
.name = "ldcp_cc_param",
.attrs = ldcp_param_attrs,
.is_visible = scc_attr_is_visible,
};
#define HNS_PORT_HC3_CC_ATTR_RW(_name, NAME) \
struct hns_port_cc_attr hns_roce_port_attr_hc3_##_name = \
__HNS_SCC_ATTR(_name, HNS_ROCE_SCC_ALGO_HC3, \
HNS_ROCE_HC3_##NAME##_OFS, \
HNS_ROCE_HC3_##NAME##_SZ, \
0, HNS_ROCE_HC3_##NAME##_MAX)
HNS_PORT_HC3_CC_ATTR_RW(initial_window, INITIAL_WINDOW);
HNS_PORT_HC3_CC_ATTR_RW(bandwidth, BANDWIDTH);
HNS_PORT_HC3_CC_ATTR_RW(qlen_shift, QLEN_SHIFT);
HNS_PORT_HC3_CC_ATTR_RW(port_usage_shift, PORT_USAGE_SHIFT);
HNS_PORT_HC3_CC_ATTR_RW(over_period, OVER_PERIOD);
HNS_PORT_HC3_CC_ATTR_RW(max_stage, MAX_STAGE);
HNS_PORT_HC3_CC_ATTR_RW(gamma_shift, GAMMA_SHIFT);
HNS_PORT_HC3_CC_ATTR_RW(lifespan, LIFESPAN);
static struct attribute *hc3_param_attrs[] = {
&hns_roce_port_attr_hc3_initial_window.port_attr.attr,
&hns_roce_port_attr_hc3_bandwidth.port_attr.attr,
&hns_roce_port_attr_hc3_qlen_shift.port_attr.attr,
&hns_roce_port_attr_hc3_port_usage_shift.port_attr.attr,
&hns_roce_port_attr_hc3_over_period.port_attr.attr,
&hns_roce_port_attr_hc3_max_stage.port_attr.attr,
&hns_roce_port_attr_hc3_gamma_shift.port_attr.attr,
&hns_roce_port_attr_hc3_lifespan.port_attr.attr,
NULL,
};
static const struct attribute_group hc3_cc_param_group = {
.name = "hc3_cc_param",
.attrs = hc3_param_attrs,
.is_visible = scc_attr_is_visible,
};
#define HNS_PORT_DIP_CC_ATTR_RW(_name, NAME) \
struct hns_port_cc_attr hns_roce_port_attr_dip_##_name = \
__HNS_SCC_ATTR(_name, HNS_ROCE_SCC_ALGO_DIP, \
HNS_ROCE_DIP_##NAME##_OFS, \
HNS_ROCE_DIP_##NAME##_SZ, \
0, HNS_ROCE_DIP_##NAME##_MAX)
HNS_PORT_DIP_CC_ATTR_RW(ai, AI);
HNS_PORT_DIP_CC_ATTR_RW(f, F);
HNS_PORT_DIP_CC_ATTR_RW(tkp, TKP);
HNS_PORT_DIP_CC_ATTR_RW(tmp, TMP);
HNS_PORT_DIP_CC_ATTR_RW(alp, ALP);
HNS_PORT_DIP_CC_ATTR_RW(max_speed, MAX_SPEED);
HNS_PORT_DIP_CC_ATTR_RW(g, G);
HNS_PORT_DIP_CC_ATTR_RW(al, AL);
HNS_PORT_DIP_CC_ATTR_RW(cnp_time, CNP_TIME);
HNS_PORT_DIP_CC_ATTR_RW(ashift, ASHIFT);
HNS_PORT_DIP_CC_ATTR_RW(lifespan, LIFESPAN);
static struct attribute *dip_param_attrs[] = {
&hns_roce_port_attr_dip_ai.port_attr.attr,
&hns_roce_port_attr_dip_f.port_attr.attr,
&hns_roce_port_attr_dip_tkp.port_attr.attr,
&hns_roce_port_attr_dip_tmp.port_attr.attr,
&hns_roce_port_attr_dip_alp.port_attr.attr,
&hns_roce_port_attr_dip_max_speed.port_attr.attr,
&hns_roce_port_attr_dip_g.port_attr.attr,
&hns_roce_port_attr_dip_al.port_attr.attr,
&hns_roce_port_attr_dip_cnp_time.port_attr.attr,
&hns_roce_port_attr_dip_ashift.port_attr.attr,
&hns_roce_port_attr_dip_lifespan.port_attr.attr,
NULL,
};
static const struct attribute_group dip_cc_param_group = {
.name = "dip_cc_param",
.attrs = dip_param_attrs,
.is_visible = scc_attr_is_visible,
};
const struct attribute_group *hns_attr_port_groups[] = {
&dcqcn_cc_param_group,
&ldcp_cc_param_group,
&hc3_cc_param_group,
&dip_cc_param_group,
NULL,
};