681 lines
20 KiB
C
681 lines
20 KiB
C
// SPDX-License-Identifier: GPL-2.0
|
|
/*
|
|
* Copyright (C) 2021 - 2023, Shanghai Yunsilicon Technology Co., Ltd.
|
|
* All rights reserved.
|
|
*/
|
|
|
|
#include <linux/module.h>
|
|
#include <linux/init.h>
|
|
#include <linux/mm.h>
|
|
#include <linux/device.h>
|
|
#include "common/xsc_core.h"
|
|
#include "common/xsc_ioctl.h"
|
|
#include "common/xsc_hsi.h"
|
|
#include "common/xsc_port_ctrl.h"
|
|
#include "global.h"
|
|
#include "xsc_ib.h"
|
|
|
|
#define XSC_RDMA_CTRL_NAME "rdma_ctrl"
|
|
|
|
static void encode_cc_cmd_enable_rp(void *data, u32 mac_port)
|
|
{
|
|
struct xsc_cc_cmd_enable_rp *cc_cmd = (struct xsc_cc_cmd_enable_rp *)data;
|
|
|
|
cc_cmd->cmd = __cpu_to_be16(cc_cmd->cmd);
|
|
cc_cmd->len = __cpu_to_be16(cc_cmd->len);
|
|
cc_cmd->enable = __cpu_to_be32(cc_cmd->enable);
|
|
cc_cmd->section = __cpu_to_be32(mac_port);
|
|
}
|
|
|
|
static void encode_cc_cmd_enable_np(void *data, u32 mac_port)
|
|
{
|
|
struct xsc_cc_cmd_enable_np *cc_cmd = (struct xsc_cc_cmd_enable_np *)data;
|
|
|
|
cc_cmd->cmd = __cpu_to_be16(cc_cmd->cmd);
|
|
cc_cmd->len = __cpu_to_be16(cc_cmd->len);
|
|
cc_cmd->enable = __cpu_to_be32(cc_cmd->enable);
|
|
cc_cmd->section = __cpu_to_be32(mac_port);
|
|
}
|
|
|
|
static void encode_cc_cmd_init_alpha(void *data, u32 mac_port)
|
|
{
|
|
struct xsc_cc_cmd_init_alpha *cc_cmd = (struct xsc_cc_cmd_init_alpha *)data;
|
|
|
|
cc_cmd->cmd = __cpu_to_be16(cc_cmd->cmd);
|
|
cc_cmd->len = __cpu_to_be16(cc_cmd->len);
|
|
cc_cmd->alpha = __cpu_to_be32(cc_cmd->alpha);
|
|
cc_cmd->section = __cpu_to_be32(mac_port);
|
|
}
|
|
|
|
static void encode_cc_cmd_g(void *data, u32 mac_port)
|
|
{
|
|
struct xsc_cc_cmd_g *cc_cmd = (struct xsc_cc_cmd_g *)data;
|
|
|
|
cc_cmd->cmd = __cpu_to_be16(cc_cmd->cmd);
|
|
cc_cmd->len = __cpu_to_be16(cc_cmd->len);
|
|
cc_cmd->g = __cpu_to_be32(cc_cmd->g);
|
|
cc_cmd->section = __cpu_to_be32(mac_port);
|
|
}
|
|
|
|
static void encode_cc_cmd_ai(void *data, u32 mac_port)
|
|
{
|
|
struct xsc_cc_cmd_ai *cc_cmd = (struct xsc_cc_cmd_ai *)data;
|
|
|
|
cc_cmd->cmd = __cpu_to_be16(cc_cmd->cmd);
|
|
cc_cmd->len = __cpu_to_be16(cc_cmd->len);
|
|
cc_cmd->ai = __cpu_to_be32(cc_cmd->ai);
|
|
cc_cmd->section = __cpu_to_be32(mac_port);
|
|
}
|
|
|
|
static void encode_cc_cmd_hai(void *data, u32 mac_port)
|
|
{
|
|
struct xsc_cc_cmd_hai *cc_cmd = (struct xsc_cc_cmd_hai *)data;
|
|
|
|
cc_cmd->cmd = __cpu_to_be16(cc_cmd->cmd);
|
|
cc_cmd->len = __cpu_to_be16(cc_cmd->len);
|
|
cc_cmd->hai = __cpu_to_be32(cc_cmd->hai);
|
|
cc_cmd->section = __cpu_to_be32(mac_port);
|
|
}
|
|
|
|
static void encode_cc_cmd_th(void *data, u32 mac_port)
|
|
{
|
|
struct xsc_cc_cmd_th *cc_cmd = (struct xsc_cc_cmd_th *)data;
|
|
|
|
cc_cmd->cmd = __cpu_to_be16(cc_cmd->cmd);
|
|
cc_cmd->len = __cpu_to_be16(cc_cmd->len);
|
|
cc_cmd->threshold = __cpu_to_be32(cc_cmd->threshold);
|
|
cc_cmd->section = __cpu_to_be32(mac_port);
|
|
}
|
|
|
|
static void encode_cc_cmd_bc(void *data, u32 mac_port)
|
|
{
|
|
struct xsc_cc_cmd_bc *cc_cmd = (struct xsc_cc_cmd_bc *)data;
|
|
|
|
cc_cmd->cmd = __cpu_to_be16(cc_cmd->cmd);
|
|
cc_cmd->len = __cpu_to_be16(cc_cmd->len);
|
|
cc_cmd->bytecount = __cpu_to_be32(cc_cmd->bytecount);
|
|
cc_cmd->section = __cpu_to_be32(mac_port);
|
|
}
|
|
|
|
static void encode_cc_cmd_cnp_opcode(void *data, u32 mac_port)
|
|
{
|
|
struct xsc_cc_cmd_cnp_opcode *cc_cmd = (struct xsc_cc_cmd_cnp_opcode *)data;
|
|
|
|
cc_cmd->opcode = __cpu_to_be32(cc_cmd->opcode);
|
|
}
|
|
|
|
static void encode_cc_cmd_cnp_bth_b(void *data, u32 mac_port)
|
|
{
|
|
struct xsc_cc_cmd_cnp_bth_b *cc_cmd = (struct xsc_cc_cmd_cnp_bth_b *)data;
|
|
|
|
cc_cmd->cmd = __cpu_to_be16(cc_cmd->cmd);
|
|
cc_cmd->len = __cpu_to_be16(cc_cmd->len);
|
|
cc_cmd->bth_b = __cpu_to_be32(cc_cmd->bth_b);
|
|
}
|
|
|
|
static void encode_cc_cmd_cnp_bth_f(void *data, u32 mac_port)
|
|
{
|
|
struct xsc_cc_cmd_cnp_bth_f *cc_cmd = (struct xsc_cc_cmd_cnp_bth_f *)data;
|
|
|
|
cc_cmd->cmd = __cpu_to_be16(cc_cmd->cmd);
|
|
cc_cmd->len = __cpu_to_be16(cc_cmd->len);
|
|
cc_cmd->bth_f = __cpu_to_be32(cc_cmd->bth_f);
|
|
}
|
|
|
|
static void encode_cc_cmd_cnp_ecn(void *data, u32 mac_port)
|
|
{
|
|
struct xsc_cc_cmd_cnp_ecn *cc_cmd = (struct xsc_cc_cmd_cnp_ecn *)data;
|
|
|
|
cc_cmd->ecn = __cpu_to_be32(cc_cmd->ecn);
|
|
}
|
|
|
|
static void encode_cc_cmd_data_ecn(void *data, u32 mac_port)
|
|
{
|
|
struct xsc_cc_cmd_data_ecn *cc_cmd = (struct xsc_cc_cmd_data_ecn *)data;
|
|
|
|
cc_cmd->cmd = __cpu_to_be16(cc_cmd->cmd);
|
|
cc_cmd->len = __cpu_to_be16(cc_cmd->len);
|
|
cc_cmd->ecn = __cpu_to_be32(cc_cmd->ecn);
|
|
}
|
|
|
|
static void encode_cc_cmd_cnp_tx_interval(void *data, u32 mac_port)
|
|
{
|
|
struct xsc_cc_cmd_cnp_tx_interval *cc_cmd = (struct xsc_cc_cmd_cnp_tx_interval *)data;
|
|
|
|
cc_cmd->cmd = __cpu_to_be16(cc_cmd->cmd);
|
|
cc_cmd->len = __cpu_to_be16(cc_cmd->len);
|
|
cc_cmd->interval = __cpu_to_be32(cc_cmd->interval);
|
|
cc_cmd->section = __cpu_to_be32(mac_port);
|
|
}
|
|
|
|
static void encode_cc_cmd_evt_rsttime(void *data, u32 mac_port)
|
|
{
|
|
struct xsc_cc_cmd_evt_rsttime *cc_cmd =
|
|
(struct xsc_cc_cmd_evt_rsttime *)data;
|
|
|
|
cc_cmd->cmd = __cpu_to_be16(cc_cmd->cmd);
|
|
cc_cmd->len = __cpu_to_be16(cc_cmd->len);
|
|
cc_cmd->period = __cpu_to_be32(cc_cmd->period);
|
|
}
|
|
|
|
static void encode_cc_cmd_cnp_dscp(void *data, u32 mac_port)
|
|
{
|
|
struct xsc_cc_cmd_cnp_dscp *cc_cmd = (struct xsc_cc_cmd_cnp_dscp *)data;
|
|
|
|
cc_cmd->cmd = __cpu_to_be16(cc_cmd->cmd);
|
|
cc_cmd->len = __cpu_to_be16(cc_cmd->len);
|
|
cc_cmd->dscp = __cpu_to_be32(cc_cmd->dscp);
|
|
cc_cmd->section = __cpu_to_be32(mac_port);
|
|
}
|
|
|
|
static void encode_cc_cmd_cnp_pcp(void *data, u32 mac_port)
|
|
{
|
|
struct xsc_cc_cmd_cnp_pcp *cc_cmd = (struct xsc_cc_cmd_cnp_pcp *)data;
|
|
|
|
cc_cmd->cmd = __cpu_to_be16(cc_cmd->cmd);
|
|
cc_cmd->len = __cpu_to_be16(cc_cmd->len);
|
|
cc_cmd->pcp = __cpu_to_be32(cc_cmd->pcp);
|
|
cc_cmd->section = __cpu_to_be32(mac_port);
|
|
}
|
|
|
|
static void encode_cc_cmd_evt_period_alpha(void *data, u32 mac_port)
|
|
{
|
|
struct xsc_cc_cmd_evt_period_alpha *cc_cmd = (struct xsc_cc_cmd_evt_period_alpha *)data;
|
|
|
|
cc_cmd->cmd = __cpu_to_be16(cc_cmd->cmd);
|
|
cc_cmd->len = __cpu_to_be16(cc_cmd->len);
|
|
cc_cmd->period = __cpu_to_be32(cc_cmd->period);
|
|
}
|
|
|
|
static void encode_cc_cmd_clamp_tgt_rate(void *data, u32 mac_port)
|
|
{
|
|
struct xsc_cc_cmd_clamp_tgt_rate *cc_cmd = (struct xsc_cc_cmd_clamp_tgt_rate *)data;
|
|
|
|
cc_cmd->cmd = __cpu_to_be16(cc_cmd->cmd);
|
|
cc_cmd->len = __cpu_to_be16(cc_cmd->len);
|
|
cc_cmd->clamp_tgt_rate = __cpu_to_be32(cc_cmd->clamp_tgt_rate);
|
|
cc_cmd->section = __cpu_to_be32(mac_port);
|
|
}
|
|
|
|
static void encode_cc_cmd_max_hai_factor(void *data, u32 mac_port)
|
|
{
|
|
struct xsc_cc_cmd_max_hai_factor *cc_cmd = (struct xsc_cc_cmd_max_hai_factor *)data;
|
|
|
|
cc_cmd->cmd = __cpu_to_be16(cc_cmd->cmd);
|
|
cc_cmd->len = __cpu_to_be16(cc_cmd->len);
|
|
cc_cmd->max_hai_factor = __cpu_to_be32(cc_cmd->max_hai_factor);
|
|
cc_cmd->section = __cpu_to_be32(mac_port);
|
|
}
|
|
|
|
static void encode_cc_get_cfg(void *data, u32 mac_port)
|
|
{
|
|
struct xsc_cc_cmd_get_cfg *cc_cmd = (struct xsc_cc_cmd_get_cfg *)data;
|
|
|
|
cc_cmd->cmd = __cpu_to_be16(cc_cmd->cmd);
|
|
cc_cmd->len = __cpu_to_be16(cc_cmd->len);
|
|
cc_cmd->section = __cpu_to_be32(mac_port);
|
|
}
|
|
|
|
static void decode_cc_get_cfg(void *data)
|
|
{
|
|
struct xsc_cc_cmd_get_cfg *cc_cmd = (struct xsc_cc_cmd_get_cfg *)data;
|
|
|
|
cc_cmd->cmd = __be16_to_cpu(cc_cmd->cmd);
|
|
cc_cmd->len = __be16_to_cpu(cc_cmd->len);
|
|
cc_cmd->enable_rp = __be32_to_cpu(cc_cmd->enable_rp);
|
|
cc_cmd->enable_np = __be32_to_cpu(cc_cmd->enable_np);
|
|
cc_cmd->init_alpha = __be32_to_cpu(cc_cmd->init_alpha);
|
|
cc_cmd->g = __be32_to_cpu(cc_cmd->g);
|
|
cc_cmd->ai = __be32_to_cpu(cc_cmd->ai);
|
|
cc_cmd->hai = __be32_to_cpu(cc_cmd->hai);
|
|
cc_cmd->threshold = __be32_to_cpu(cc_cmd->threshold);
|
|
cc_cmd->bytecount = __be32_to_cpu(cc_cmd->bytecount);
|
|
cc_cmd->opcode = __be32_to_cpu(cc_cmd->opcode);
|
|
cc_cmd->bth_b = __be32_to_cpu(cc_cmd->bth_b);
|
|
cc_cmd->bth_f = __be32_to_cpu(cc_cmd->bth_f);
|
|
cc_cmd->cnp_ecn = __be32_to_cpu(cc_cmd->cnp_ecn);
|
|
cc_cmd->data_ecn = __be32_to_cpu(cc_cmd->data_ecn);
|
|
cc_cmd->cnp_tx_interval = __be32_to_cpu(cc_cmd->cnp_tx_interval);
|
|
cc_cmd->evt_period_rsttime = __be32_to_cpu(cc_cmd->evt_period_rsttime);
|
|
cc_cmd->cnp_dscp = __be32_to_cpu(cc_cmd->cnp_dscp);
|
|
cc_cmd->cnp_pcp = __be32_to_cpu(cc_cmd->cnp_pcp);
|
|
cc_cmd->evt_period_alpha = __be32_to_cpu(cc_cmd->evt_period_alpha);
|
|
cc_cmd->clamp_tgt_rate = __be32_to_cpu(cc_cmd->clamp_tgt_rate);
|
|
cc_cmd->max_hai_factor = __be32_to_cpu(cc_cmd->max_hai_factor);
|
|
cc_cmd->section = __be32_to_cpu(cc_cmd->section);
|
|
}
|
|
|
|
static void encode_cc_get_stat(void *data, u32 mac_port)
|
|
{
|
|
struct xsc_cc_cmd_get_stat *cc_cmd = (struct xsc_cc_cmd_get_stat *)data;
|
|
|
|
cc_cmd->cmd = __cpu_to_be16(cc_cmd->cmd);
|
|
cc_cmd->len = __cpu_to_be16(cc_cmd->len);
|
|
cc_cmd->section = __cpu_to_be32(mac_port);
|
|
}
|
|
|
|
static void decode_cc_get_stat(void *data)
|
|
{
|
|
struct xsc_cc_cmd_stat *cc_cmd = (struct xsc_cc_cmd_stat *)data;
|
|
|
|
cc_cmd->cnp_handled = __be32_to_cpu(cc_cmd->cnp_handled);
|
|
cc_cmd->alpha_recovery = __be32_to_cpu(cc_cmd->alpha_recovery);
|
|
cc_cmd->reset_timeout = __be32_to_cpu(cc_cmd->reset_timeout);
|
|
cc_cmd->reset_bytecount = __be32_to_cpu(cc_cmd->reset_bytecount);
|
|
}
|
|
|
|
static int xsc_priv_dev_ioctl_get_global_pcp(struct xsc_core_device *xdev, void *in, void *out)
|
|
{
|
|
struct xsc_ioctl_global_pcp *resp = (struct xsc_ioctl_global_pcp *)out;
|
|
|
|
resp->pcp = get_global_force_pcp();
|
|
return 0;
|
|
}
|
|
|
|
static int xsc_priv_dev_ioctl_get_global_dscp(struct xsc_core_device *xdev, void *in, void *out)
|
|
{
|
|
struct xsc_ioctl_global_dscp *resp = (struct xsc_ioctl_global_dscp *)out;
|
|
|
|
resp->dscp = get_global_force_dscp();
|
|
return 0;
|
|
}
|
|
|
|
static int xsc_priv_dev_ioctl_set_global_pcp(struct xsc_core_device *xdev, void *in, void *out)
|
|
{
|
|
int ret = 0;
|
|
struct xsc_ioctl_global_pcp *req = (struct xsc_ioctl_global_pcp *)out;
|
|
|
|
ret = set_global_force_pcp(req->pcp);
|
|
return ret;
|
|
}
|
|
|
|
static int xsc_priv_dev_ioctl_set_global_dscp(struct xsc_core_device *xdev, void *in, void *out)
|
|
{
|
|
int ret = 0;
|
|
struct xsc_ioctl_global_dscp *req = (struct xsc_ioctl_global_dscp *)out;
|
|
|
|
ret = set_global_force_dscp(req->dscp);
|
|
return ret;
|
|
}
|
|
|
|
static int xsc_priv_dev_ioctl_get_cma_pcp(struct xsc_core_device *xdev, void *in, void *out)
|
|
{
|
|
struct xsc_ib_dev *ib_dev = xdev->xsc_ib_dev;
|
|
struct xsc_ioctl_cma_pcp *resp = (struct xsc_ioctl_cma_pcp *)out;
|
|
|
|
if (!check_is_pf(&xdev->caps, xdev->glb_func_id))
|
|
return -EOPNOTSUPP;
|
|
|
|
resp->pcp = ib_dev->cm_pcp;
|
|
return 0;
|
|
}
|
|
|
|
static int xsc_priv_dev_ioctl_get_cma_dscp(struct xsc_core_device *xdev, void *in, void *out)
|
|
{
|
|
struct xsc_ib_dev *ib_dev = xdev->xsc_ib_dev;
|
|
struct xsc_ioctl_cma_dscp *resp = (struct xsc_ioctl_cma_dscp *)out;
|
|
|
|
if (!check_is_pf(&xdev->caps, xdev->glb_func_id))
|
|
return -EOPNOTSUPP;
|
|
|
|
resp->dscp = ib_dev->cm_dscp;
|
|
return 0;
|
|
}
|
|
|
|
static int xsc_priv_dev_ioctl_set_cma_pcp(struct xsc_core_device *xdev, void *in, void *out)
|
|
{
|
|
struct xsc_ib_dev *ib_dev = xdev->xsc_ib_dev;
|
|
struct xsc_ioctl_cma_pcp *req = (struct xsc_ioctl_cma_pcp *)out;
|
|
|
|
if (!check_is_pf(&xdev->caps, xdev->glb_func_id))
|
|
return -EOPNOTSUPP;
|
|
|
|
if (req->pcp < 0 || (req->pcp > QOS_PCP_MAX && req->pcp != DSCP_PCP_UNSET))
|
|
return -EINVAL;
|
|
|
|
ib_dev->cm_pcp = req->pcp;
|
|
return 0;
|
|
}
|
|
|
|
static int xsc_priv_dev_ioctl_set_cma_dscp(struct xsc_core_device *xdev, void *in, void *out)
|
|
{
|
|
struct xsc_ib_dev *ib_dev = xdev->xsc_ib_dev;
|
|
struct xsc_ioctl_cma_dscp *req = (struct xsc_ioctl_cma_dscp *)out;
|
|
|
|
if (!check_is_pf(&xdev->caps, xdev->glb_func_id))
|
|
return -EOPNOTSUPP;
|
|
|
|
if (req->dscp < 0 || (req->dscp > QOS_DSCP_MAX && req->dscp != DSCP_PCP_UNSET))
|
|
return -EINVAL;
|
|
|
|
ib_dev->cm_dscp = req->dscp;
|
|
return 0;
|
|
}
|
|
|
|
static int _rdma_ctrl_ioctl_cc(struct xsc_core_device *xdev,
|
|
struct xsc_ioctl_hdr __user *user_hdr, struct xsc_ioctl_hdr *hdr,
|
|
u16 expect_req_size, u16 expect_resp_size,
|
|
void (*encode)(void *, u32), void (*decode)(void *))
|
|
{
|
|
struct xsc_cc_mbox_in *in;
|
|
struct xsc_cc_mbox_out *out;
|
|
u16 user_size;
|
|
int err;
|
|
|
|
user_size = expect_req_size > expect_resp_size ? expect_req_size : expect_resp_size;
|
|
if (hdr->attr.length != user_size)
|
|
return -EINVAL;
|
|
|
|
in = kvzalloc(sizeof(struct xsc_cc_mbox_in) + expect_req_size, GFP_KERNEL);
|
|
if (!in)
|
|
goto err_in;
|
|
out = kvzalloc(sizeof(struct xsc_cc_mbox_out) + expect_resp_size, GFP_KERNEL);
|
|
if (!out)
|
|
goto err_out;
|
|
|
|
err = copy_from_user(&in->data, user_hdr->attr.data, expect_req_size);
|
|
if (err)
|
|
goto err;
|
|
|
|
in->hdr.opcode = __cpu_to_be16(hdr->attr.opcode);
|
|
if (encode)
|
|
encode((void *)in->data, xdev->mac_port);
|
|
|
|
err = xsc_cmd_exec(xdev, in, sizeof(*in) + expect_req_size, out,
|
|
sizeof(*out) + expect_resp_size);
|
|
|
|
hdr->attr.error = __be32_to_cpu(out->hdr.status);
|
|
if (decode)
|
|
decode((void *)out->data);
|
|
|
|
if (copy_to_user((void *)user_hdr, hdr, sizeof(*hdr)))
|
|
goto err;
|
|
if (copy_to_user((void *)user_hdr->attr.data, &out->data, expect_resp_size))
|
|
goto err;
|
|
|
|
kvfree(in);
|
|
kvfree(out);
|
|
return 0;
|
|
|
|
err:
|
|
kvfree(out);
|
|
err_out:
|
|
kvfree(in);
|
|
err_in:
|
|
return -EFAULT;
|
|
}
|
|
|
|
int _rdma_ctrl_exec_ioctl(struct xsc_core_device *xdev, void *in, int in_size, void *out,
|
|
int out_size)
|
|
{
|
|
int opcode, ret = 0;
|
|
struct xsc_ioctl_attr *hdr;
|
|
|
|
hdr = (struct xsc_ioctl_attr *)in;
|
|
opcode = hdr->opcode;
|
|
switch (opcode) {
|
|
case XSC_IOCTL_GET_GLOBAL_PCP:
|
|
ret = xsc_priv_dev_ioctl_get_global_pcp(xdev, in, out);
|
|
break;
|
|
case XSC_IOCTL_GET_GLOBAL_DSCP:
|
|
ret = xsc_priv_dev_ioctl_get_global_dscp(xdev, in, out);
|
|
break;
|
|
case XSC_IOCTL_GET_CMA_PCP:
|
|
ret = xsc_priv_dev_ioctl_get_cma_pcp(xdev, in, out);
|
|
break;
|
|
case XSC_IOCTL_GET_CMA_DSCP:
|
|
ret = xsc_priv_dev_ioctl_get_cma_dscp(xdev, in, out);
|
|
break;
|
|
case XSC_IOCTL_SET_GLOBAL_PCP:
|
|
xsc_core_dbg(xdev, "setting global pcp\n");
|
|
ret = xsc_priv_dev_ioctl_set_global_pcp(xdev, in, out);
|
|
break;
|
|
case XSC_IOCTL_SET_GLOBAL_DSCP:
|
|
xsc_core_dbg(xdev, "setting global dscp\n");
|
|
ret = xsc_priv_dev_ioctl_set_global_dscp(xdev, in, out);
|
|
break;
|
|
case XSC_IOCTL_SET_CMA_PCP:
|
|
ret = xsc_priv_dev_ioctl_set_cma_pcp(xdev, in, out);
|
|
break;
|
|
case XSC_IOCTL_SET_CMA_DSCP:
|
|
ret = xsc_priv_dev_ioctl_set_cma_dscp(xdev, in, out);
|
|
break;
|
|
default:
|
|
ret = -EINVAL;
|
|
break;
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
static long _rdma_ctrl_ioctl_getinfo(struct xsc_core_device *xdev,
|
|
struct xsc_ioctl_hdr __user *user_hdr)
|
|
{
|
|
struct xsc_ioctl_hdr hdr;
|
|
struct xsc_ioctl_hdr *in;
|
|
int in_size;
|
|
int err;
|
|
|
|
err = copy_from_user(&hdr, user_hdr, sizeof(hdr));
|
|
if (err)
|
|
return -EFAULT;
|
|
if (hdr.check_filed != XSC_IOCTL_CHECK_FILED)
|
|
return -EINVAL;
|
|
switch (hdr.attr.opcode) {
|
|
case XSC_IOCTL_GET_GLOBAL_PCP:
|
|
case XSC_IOCTL_GET_GLOBAL_DSCP:
|
|
case XSC_IOCTL_SET_GLOBAL_PCP:
|
|
case XSC_IOCTL_SET_GLOBAL_DSCP:
|
|
case XSC_IOCTL_GET_CMA_PCP:
|
|
case XSC_IOCTL_GET_CMA_DSCP:
|
|
case XSC_IOCTL_SET_CMA_PCP:
|
|
case XSC_IOCTL_SET_CMA_DSCP:
|
|
break;
|
|
default:
|
|
return -EINVAL;
|
|
}
|
|
in_size = sizeof(struct xsc_ioctl_hdr) + hdr.attr.length;
|
|
in = kvzalloc(in_size, GFP_KERNEL);
|
|
if (!in)
|
|
return -EFAULT;
|
|
in->attr.opcode = hdr.attr.opcode;
|
|
in->attr.length = hdr.attr.length;
|
|
err = copy_from_user(in->attr.data, user_hdr->attr.data, hdr.attr.length);
|
|
if (err) {
|
|
kvfree(in);
|
|
return -EFAULT;
|
|
}
|
|
|
|
err = _rdma_ctrl_exec_ioctl(xdev, &in->attr, (in_size - sizeof(u32)), in->attr.data,
|
|
hdr.attr.length);
|
|
in->attr.error = err;
|
|
if (copy_to_user(user_hdr, in, in_size))
|
|
err = -EFAULT;
|
|
kvfree(in);
|
|
return err;
|
|
}
|
|
|
|
static long _rdma_ctrl_ioctl_cmdq(struct xsc_core_device *xdev,
|
|
struct xsc_ioctl_hdr __user *user_hdr)
|
|
{
|
|
struct xsc_ioctl_hdr hdr;
|
|
int err;
|
|
void *in;
|
|
void *out;
|
|
|
|
err = copy_from_user(&hdr, user_hdr, sizeof(hdr));
|
|
if (err)
|
|
return -EFAULT;
|
|
|
|
/* check valid */
|
|
if (hdr.check_filed != XSC_IOCTL_CHECK_FILED)
|
|
return -EINVAL;
|
|
|
|
/* check ioctl cmd */
|
|
switch (hdr.attr.opcode) {
|
|
case XSC_CMD_OP_IOCTL_SET_ENABLE_RP:
|
|
return _rdma_ctrl_ioctl_cc(xdev, user_hdr, &hdr,
|
|
sizeof(struct xsc_cc_cmd_enable_rp),
|
|
0, encode_cc_cmd_enable_rp, NULL);
|
|
case XSC_CMD_OP_IOCTL_SET_ENABLE_NP:
|
|
return _rdma_ctrl_ioctl_cc(xdev, user_hdr, &hdr,
|
|
sizeof(struct xsc_cc_cmd_enable_np),
|
|
0, encode_cc_cmd_enable_np, NULL);
|
|
case XSC_CMD_OP_IOCTL_SET_INIT_ALPHA:
|
|
return _rdma_ctrl_ioctl_cc(xdev, user_hdr, &hdr,
|
|
sizeof(struct xsc_cc_cmd_init_alpha),
|
|
0, encode_cc_cmd_init_alpha, NULL);
|
|
case XSC_CMD_OP_IOCTL_SET_G:
|
|
return _rdma_ctrl_ioctl_cc(xdev, user_hdr, &hdr,
|
|
sizeof(struct xsc_cc_cmd_g),
|
|
0, encode_cc_cmd_g, NULL);
|
|
case XSC_CMD_OP_IOCTL_SET_AI:
|
|
return _rdma_ctrl_ioctl_cc(xdev, user_hdr, &hdr,
|
|
sizeof(struct xsc_cc_cmd_ai),
|
|
0, encode_cc_cmd_ai, NULL);
|
|
case XSC_CMD_OP_IOCTL_SET_HAI:
|
|
return _rdma_ctrl_ioctl_cc(xdev, user_hdr, &hdr,
|
|
sizeof(struct xsc_cc_cmd_hai),
|
|
0, encode_cc_cmd_hai, NULL);
|
|
case XSC_CMD_OP_IOCTL_SET_TH:
|
|
return _rdma_ctrl_ioctl_cc(xdev, user_hdr, &hdr,
|
|
sizeof(struct xsc_cc_cmd_th),
|
|
0, encode_cc_cmd_th, NULL);
|
|
case XSC_CMD_OP_IOCTL_SET_BC_TH:
|
|
return _rdma_ctrl_ioctl_cc(xdev, user_hdr, &hdr,
|
|
sizeof(struct xsc_cc_cmd_bc),
|
|
0, encode_cc_cmd_bc, NULL);
|
|
case XSC_CMD_OP_IOCTL_SET_CNP_OPCODE:
|
|
return _rdma_ctrl_ioctl_cc(xdev, user_hdr, &hdr,
|
|
sizeof(struct xsc_cc_cmd_cnp_opcode),
|
|
0, encode_cc_cmd_cnp_opcode, NULL);
|
|
case XSC_CMD_OP_IOCTL_SET_CNP_BTH_B:
|
|
return _rdma_ctrl_ioctl_cc(xdev, user_hdr, &hdr,
|
|
sizeof(struct xsc_cc_cmd_cnp_bth_b),
|
|
0, encode_cc_cmd_cnp_bth_b, NULL);
|
|
case XSC_CMD_OP_IOCTL_SET_CNP_BTH_F:
|
|
return _rdma_ctrl_ioctl_cc(xdev, user_hdr, &hdr,
|
|
sizeof(struct xsc_cc_cmd_cnp_bth_f),
|
|
0, encode_cc_cmd_cnp_bth_f, NULL);
|
|
case XSC_CMD_OP_IOCTL_SET_CNP_ECN:
|
|
return _rdma_ctrl_ioctl_cc(xdev, user_hdr, &hdr, sizeof(struct xsc_cc_cmd_cnp_ecn),
|
|
0, encode_cc_cmd_cnp_ecn, NULL);
|
|
case XSC_CMD_OP_IOCTL_SET_DATA_ECN:
|
|
return _rdma_ctrl_ioctl_cc(xdev, user_hdr, &hdr,
|
|
sizeof(struct xsc_cc_cmd_data_ecn),
|
|
0, encode_cc_cmd_data_ecn, NULL);
|
|
case XSC_CMD_OP_IOCTL_SET_CNP_TX_INTERVAL:
|
|
return _rdma_ctrl_ioctl_cc(xdev, user_hdr, &hdr,
|
|
sizeof(struct xsc_cc_cmd_cnp_tx_interval),
|
|
0, encode_cc_cmd_cnp_tx_interval, NULL);
|
|
case XSC_CMD_OP_IOCTL_SET_EVT_PERIOD_RSTTIME:
|
|
return _rdma_ctrl_ioctl_cc(xdev, user_hdr, &hdr,
|
|
sizeof(struct xsc_cc_cmd_evt_rsttime),
|
|
0, encode_cc_cmd_evt_rsttime, NULL);
|
|
case XSC_CMD_OP_IOCTL_SET_CNP_DSCP:
|
|
return _rdma_ctrl_ioctl_cc(xdev, user_hdr, &hdr,
|
|
sizeof(struct xsc_cc_cmd_cnp_dscp),
|
|
0, encode_cc_cmd_cnp_dscp, NULL);
|
|
case XSC_CMD_OP_IOCTL_SET_CNP_PCP:
|
|
return _rdma_ctrl_ioctl_cc(xdev, user_hdr, &hdr,
|
|
sizeof(struct xsc_cc_cmd_cnp_pcp),
|
|
0, encode_cc_cmd_cnp_pcp, NULL);
|
|
case XSC_CMD_OP_IOCTL_SET_EVT_PERIOD_ALPHA:
|
|
return _rdma_ctrl_ioctl_cc(xdev, user_hdr, &hdr,
|
|
sizeof(struct xsc_cc_cmd_evt_period_alpha),
|
|
0, encode_cc_cmd_evt_period_alpha, NULL);
|
|
case XSC_CMD_OP_IOCTL_SET_CLAMP_TGT_RATE:
|
|
return _rdma_ctrl_ioctl_cc(xdev, user_hdr, &hdr,
|
|
sizeof(struct xsc_cc_cmd_clamp_tgt_rate),
|
|
0, encode_cc_cmd_clamp_tgt_rate, NULL);
|
|
case XSC_CMD_OP_IOCTL_SET_MAX_HAI_FACTOR:
|
|
return _rdma_ctrl_ioctl_cc(xdev, user_hdr, &hdr,
|
|
sizeof(struct xsc_cc_cmd_max_hai_factor),
|
|
0, encode_cc_cmd_max_hai_factor, NULL);
|
|
case XSC_CMD_OP_IOCTL_GET_CC_CFG:
|
|
return _rdma_ctrl_ioctl_cc(xdev, user_hdr, &hdr, sizeof(struct xsc_cc_cmd_get_cfg),
|
|
sizeof(struct xsc_cc_cmd_get_cfg),
|
|
encode_cc_get_cfg, decode_cc_get_cfg);
|
|
case XSC_CMD_OP_IOCTL_GET_CC_STAT:
|
|
return _rdma_ctrl_ioctl_cc(xdev, user_hdr, &hdr, sizeof(struct xsc_cc_cmd_get_stat),
|
|
sizeof(struct xsc_cc_cmd_stat),
|
|
encode_cc_get_stat, decode_cc_get_stat);
|
|
default:
|
|
return -EINVAL;
|
|
}
|
|
|
|
in = kvzalloc(hdr.attr.length, GFP_KERNEL);
|
|
if (!in)
|
|
return -ENOMEM;
|
|
out = kvzalloc(hdr.attr.length, GFP_KERNEL);
|
|
if (!out) {
|
|
kfree(in);
|
|
return -ENOMEM;
|
|
}
|
|
|
|
err = copy_from_user(in, user_hdr->attr.data, hdr.attr.length);
|
|
if (err) {
|
|
err = -EFAULT;
|
|
goto err_exit;
|
|
}
|
|
|
|
xsc_cmd_exec(xdev, in, hdr.attr.length, out, hdr.attr.length);
|
|
|
|
if (copy_to_user((void *)user_hdr, &hdr, sizeof(hdr)))
|
|
err = -EFAULT;
|
|
if (copy_to_user((void *)user_hdr->attr.data, out, hdr.attr.length))
|
|
err = -EFAULT;
|
|
err_exit:
|
|
kfree(in);
|
|
kfree(out);
|
|
return err;
|
|
}
|
|
|
|
static int _rdma_ctrl_reg_cb(struct xsc_bdf_file *file, unsigned int cmd,
|
|
struct xsc_ioctl_hdr __user *user_hdr, void *data)
|
|
{
|
|
struct xsc_core_device *xdev = file->xdev;
|
|
int err;
|
|
|
|
switch (cmd) {
|
|
case XSC_IOCTL_CMDQ:
|
|
err = _rdma_ctrl_ioctl_cmdq(xdev, user_hdr);
|
|
break;
|
|
case XSC_IOCTL_DRV_GET:
|
|
case XSC_IOCTL_DRV_SET:
|
|
err = _rdma_ctrl_ioctl_getinfo(xdev, user_hdr);
|
|
break;
|
|
default:
|
|
err = -EFAULT;
|
|
break;
|
|
}
|
|
|
|
return err;
|
|
}
|
|
|
|
static void _rdma_ctrl_reg_fini(void)
|
|
{
|
|
xsc_port_ctrl_cb_dereg(XSC_RDMA_CTRL_NAME);
|
|
}
|
|
|
|
static int _rdma_ctrl_reg_init(void)
|
|
{
|
|
int ret;
|
|
|
|
ret = xsc_port_ctrl_cb_reg(XSC_RDMA_CTRL_NAME, _rdma_ctrl_reg_cb, NULL);
|
|
if (ret != 0)
|
|
pr_err("failed to register port control node for %s\n", XSC_RDMA_CTRL_NAME);
|
|
|
|
return ret;
|
|
}
|
|
|
|
void xsc_rdma_ctrl_fini(void)
|
|
{
|
|
_rdma_ctrl_reg_fini();
|
|
}
|
|
|
|
int xsc_rdma_ctrl_init(void)
|
|
{
|
|
return _rdma_ctrl_reg_init();
|
|
}
|
|
|