提交 55508c9f 编写于 作者: K Kai Ye 提交者: Zheng Zengkai

crypto: hisilicon/qm - supports writing QoS int the host

mainline inclusion
from mainline-master
commit 72b010dc
category: feature
bugzilla: 173981
CVE: NA

Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=72b010dc33b9598883bc84d40b0a9d07c16f5e39

----------------------------------------------------------------------

Based on the Token bucket algorithm. The HAC driver supports to configure
each function's QoS in the host. The driver supports writing QoS by the
debugfs node that named "alg_qos". The qos value is 1~1000.
Signed-off-by: NKai Ye <yekai13@huawei.com>
Signed-off-by: NHerbert Xu <herbert@gondor.apana.org.au>
Signed-off-by: NMingqiang Ling <lingmingqiang@huawei.com>
Signed-off-by: NZheng Zengkai <zhengzengkai@huawei.com>
上级 47865d31
......@@ -240,6 +240,32 @@
#define QM_DRIVER_REMOVING 0
#define QM_RST_SCHED 1
#define QM_RESETTING 2
#define QM_QOS_PARAM_NUM 2
#define QM_QOS_VAL_NUM 1
#define QM_QOS_BDF_PARAM_NUM 4
#define QM_QOS_MAX_VAL 1000
#define QM_QOS_RATE 100
#define QM_QOS_EXPAND_RATE 1000
#define QM_SHAPER_CIR_B_MASK GENMASK(7, 0)
#define QM_SHAPER_CIR_U_MASK GENMASK(10, 8)
#define QM_SHAPER_CIR_S_MASK GENMASK(14, 11)
#define QM_SHAPER_FACTOR_CIR_U_SHIFT 8
#define QM_SHAPER_FACTOR_CIR_S_SHIFT 11
#define QM_SHAPER_FACTOR_CBS_B_SHIFT 15
#define QM_SHAPER_FACTOR_CBS_S_SHIFT 19
#define QM_SHAPER_CBS_B 1
#define QM_SHAPER_CBS_S 16
#define QM_SHAPER_VFT_OFFSET 6
#define QM_QOS_MIN_ERROR_RATE 5
#define QM_QOS_TYPICAL_NUM 8
#define QM_SHAPER_MIN_CBS_S 8
#define QM_QOS_TICK 0x300U
#define QM_QOS_DIVISOR_CLK 0x1f40U
#define QM_QOS_MAX_CIR_B 200
#define QM_QOS_MIN_CIR_B 100
#define QM_QOS_MAX_CIR_U 6
#define QM_QOS_MAX_CIR_S 11
#define QM_QOS_VAL_MAX_LEN 32
#define QM_MK_CQC_DW3_V1(hop_num, pg_sz, buf_sz, cqe_sz) \
(((hop_num) << QM_CQ_HOP_NUM_SHIFT) | \
......@@ -280,6 +306,7 @@
enum vft_type {
SQC_VFT = 0,
CQC_VFT,
SHAPER_VFT,
};
enum acc_err_result {
......@@ -288,6 +315,11 @@ enum acc_err_result {
ACC_ERR_RECOVERED,
};
enum qm_alg_type {
ALG_TYPE_0,
ALG_TYPE_1,
};
enum qm_mb_cmd {
QM_PF_FLR_PREPARE = 0x01,
QM_PF_SRST_PREPARE,
......@@ -460,6 +492,11 @@ static const char * const qp_s[] = {
"none", "init", "start", "stop", "close",
};
static const u32 typical_qos_val[QM_QOS_TYPICAL_NUM] = {100, 250, 500, 1000,
10000, 25000, 50000, 100000};
static const u32 typical_qos_cbs_s[QM_QOS_TYPICAL_NUM] = {9, 10, 11, 12, 16,
17, 18, 19};
static bool qm_avail_state(struct hisi_qm *qm, enum qm_state new)
{
enum qm_state curr = atomic_read(&qm->status.flags);
......@@ -899,8 +936,69 @@ static void qm_init_prefetch(struct hisi_qm *qm)
writel(page_type, qm->io_base + QM_PAGE_SIZE);
}
/*
* the formula:
* IR = X Mbps if ir = 1 means IR = 100 Mbps, if ir = 10000 means = 10Gbps
*
* IR_b * (2 ^ IR_u) * 8
* IR(Mbps) * 10 ^ -3 = -------------------------
* Tick * (2 ^ IR_s)
*/
static u32 acc_shaper_para_calc(u64 cir_b, u64 cir_u, u64 cir_s)
{
return ((cir_b * QM_QOS_DIVISOR_CLK) * (1 << cir_u)) /
(QM_QOS_TICK * (1 << cir_s));
}
static u32 acc_shaper_calc_cbs_s(u32 ir)
{
int i;
if (ir < typical_qos_val[0])
return QM_SHAPER_MIN_CBS_S;
for (i = 1; i < QM_QOS_TYPICAL_NUM; i++) {
if (ir >= typical_qos_val[i - 1] && ir < typical_qos_val[i])
return typical_qos_cbs_s[i - 1];
}
return typical_qos_cbs_s[QM_QOS_TYPICAL_NUM - 1];
}
static int qm_get_shaper_para(u32 ir, struct qm_shaper_factor *factor)
{
u32 cir_b, cir_u, cir_s, ir_calc;
u32 error_rate;
factor->cbs_s = acc_shaper_calc_cbs_s(ir);
for (cir_b = QM_QOS_MIN_CIR_B; cir_b <= QM_QOS_MAX_CIR_B; cir_b++) {
for (cir_u = 0; cir_u <= QM_QOS_MAX_CIR_U; cir_u++) {
for (cir_s = 0; cir_s <= QM_QOS_MAX_CIR_S; cir_s++) {
/** the formula is changed to:
* IR_b * (2 ^ IR_u) * DIVISOR_CLK
* IR(Mbps) = -------------------------
* 768 * (2 ^ IR_s)
*/
ir_calc = acc_shaper_para_calc(cir_b, cir_u,
cir_s);
error_rate = QM_QOS_EXPAND_RATE * (u32)abs(ir_calc - ir) / ir;
if (error_rate <= QM_QOS_MIN_ERROR_RATE) {
factor->cir_b = cir_b;
factor->cir_u = cir_u;
factor->cir_s = cir_s;
return 0;
}
}
}
}
return -EINVAL;
}
static void qm_vft_data_cfg(struct hisi_qm *qm, enum vft_type type, u32 base,
u32 number)
u32 number, struct qm_shaper_factor *factor)
{
u64 tmp = 0;
......@@ -929,6 +1027,15 @@ static void qm_vft_data_cfg(struct hisi_qm *qm, enum vft_type type, u32 base,
tmp = QM_CQC_VFT_VALID;
}
break;
case SHAPER_VFT:
if (qm->ver >= QM_HW_V3) {
tmp = factor->cir_b |
(factor->cir_u << QM_SHAPER_FACTOR_CIR_U_SHIFT) |
(factor->cir_s << QM_SHAPER_FACTOR_CIR_S_SHIFT) |
(QM_SHAPER_CBS_B << QM_SHAPER_FACTOR_CBS_B_SHIFT) |
(factor->cbs_s << QM_SHAPER_FACTOR_CBS_S_SHIFT);
}
break;
}
}
......@@ -939,6 +1046,7 @@ static void qm_vft_data_cfg(struct hisi_qm *qm, enum vft_type type, u32 base,
static int qm_set_vft_common(struct hisi_qm *qm, enum vft_type type,
u32 fun_num, u32 base, u32 number)
{
struct qm_shaper_factor *factor = &qm->factor[fun_num];
unsigned int val;
int ret;
......@@ -950,9 +1058,12 @@ static int qm_set_vft_common(struct hisi_qm *qm, enum vft_type type,
writel(0x0, qm->io_base + QM_VFT_CFG_OP_WR);
writel(type, qm->io_base + QM_VFT_CFG_TYPE);
if (type == SHAPER_VFT)
fun_num |= base << QM_SHAPER_VFT_OFFSET;
writel(fun_num, qm->io_base + QM_VFT_CFG);
qm_vft_data_cfg(qm, type, base, number);
qm_vft_data_cfg(qm, type, base, number, factor);
writel(0x0, qm->io_base + QM_VFT_CFG_RDY);
writel(0x1, qm->io_base + QM_VFT_CFG_OP_ENABLE);
......@@ -962,6 +1073,27 @@ static int qm_set_vft_common(struct hisi_qm *qm, enum vft_type type,
POLL_TIMEOUT);
}
static int qm_shaper_init_vft(struct hisi_qm *qm, u32 fun_num)
{
int ret, i;
qm->factor[fun_num].func_qos = QM_QOS_MAX_VAL;
ret = qm_get_shaper_para(QM_QOS_MAX_VAL * QM_QOS_RATE, &qm->factor[fun_num]);
if (ret) {
dev_err(&qm->pdev->dev, "failed to calculate shaper parameter!\n");
return ret;
}
writel(qm->type_rate, qm->io_base + QM_SHAPER_CFG);
for (i = ALG_TYPE_0; i <= ALG_TYPE_1; i++) {
/* The base number of queue reuse for different alg type */
ret = qm_set_vft_common(qm, SHAPER_VFT, fun_num, i, 1);
if (ret)
return ret;
}
return 0;
}
/* The config should be conducted after qm_dev_mem_reset() */
static int qm_set_sqc_cqc_vft(struct hisi_qm *qm, u32 fun_num, u32 base,
u32 number)
......@@ -974,7 +1106,21 @@ static int qm_set_sqc_cqc_vft(struct hisi_qm *qm, u32 fun_num, u32 base,
return ret;
}
/* init default shaper qos val */
if (qm->ver >= QM_HW_V3) {
ret = qm_shaper_init_vft(qm, fun_num);
if (ret)
goto back_sqc_cqc;
}
return 0;
back_sqc_cqc:
for (i = SQC_VFT; i <= CQC_VFT; i++) {
ret = qm_set_vft_common(qm, i, fun_num, 0, 0);
if (ret)
return ret;
}
return ret;
}
static int qm_get_vft_v2(struct hisi_qm *qm, u32 *base, u32 *number)
......@@ -3113,6 +3259,7 @@ void hisi_qm_uninit(struct hisi_qm *qm)
struct device *dev = &pdev->dev;
qm_cmd_uninit(qm);
kfree(qm->factor);
down_write(&qm->qps_lock);
if (!qm_avail_state(qm, QM_CLOSE)) {
......@@ -3842,6 +3989,149 @@ static int qm_clear_vft_config(struct hisi_qm *qm)
return 0;
}
static int qm_func_shaper_enable(struct hisi_qm *qm, u32 fun_index, u32 qos)
{
struct device *dev = &qm->pdev->dev;
u32 ir = qos * QM_QOS_RATE;
int ret, total_vfs, i;
total_vfs = pci_sriov_get_totalvfs(qm->pdev);
if (fun_index > total_vfs)
return -EINVAL;
qm->factor[fun_index].func_qos = qos;
ret = qm_get_shaper_para(ir, &qm->factor[fun_index]);
if (ret) {
dev_err(dev, "failed to calculate shaper parameter!\n");
return -EINVAL;
}
for (i = ALG_TYPE_0; i <= ALG_TYPE_1; i++) {
/* The base number of queue reuse for different alg type */
ret = qm_set_vft_common(qm, SHAPER_VFT, fun_index, i, 1);
if (ret) {
dev_err(dev, "type: %d, failed to set shaper vft!\n", i);
return -EINVAL;
}
}
return 0;
}
static ssize_t qm_qos_value_init(const char *buf, unsigned long *val)
{
int buflen = strlen(buf);
int ret, i;
for (i = 0; i < buflen; i++) {
if (!isdigit(buf[i]))
return -EINVAL;
}
ret = sscanf(buf, "%ld", val);
if (ret != QM_QOS_VAL_NUM)
return -EINVAL;
return 0;
}
static ssize_t qm_algqos_write(struct file *filp, const char __user *buf,
size_t count, loff_t *pos)
{
struct hisi_qm *qm = filp->private_data;
char tbuf[QM_DBG_READ_LEN];
int tmp1, bus, device, function;
char tbuf_bdf[QM_DBG_READ_LEN] = {0};
char val_buf[QM_QOS_VAL_MAX_LEN] = {0};
unsigned int fun_index;
unsigned long val = 0;
int len, ret;
if (qm->fun_type == QM_HW_VF)
return -EINVAL;
/* Mailbox and reset cannot be operated at the same time */
if (test_and_set_bit(QM_RESETTING, &qm->misc_ctl)) {
pci_err(qm->pdev, "dev resetting, write alg qos failed!\n");
return -EAGAIN;
}
if (*pos != 0) {
ret = 0;
goto err_get_status;
}
if (count >= QM_DBG_READ_LEN) {
ret = -ENOSPC;
goto err_get_status;
}
len = simple_write_to_buffer(tbuf, QM_DBG_READ_LEN - 1, pos, buf, count);
if (len < 0) {
ret = len;
goto err_get_status;
}
tbuf[len] = '\0';
ret = sscanf(tbuf, "%s %s", tbuf_bdf, val_buf);
if (ret != QM_QOS_PARAM_NUM) {
ret = -EINVAL;
goto err_get_status;
}
ret = qm_qos_value_init(val_buf, &val);
if (val == 0 || val > QM_QOS_MAX_VAL || ret) {
pci_err(qm->pdev, "input qos value is error, please set 1~1000!\n");
ret = -EINVAL;
goto err_get_status;
}
ret = sscanf(tbuf_bdf, "%d:%x:%d.%d", &tmp1, &bus, &device, &function);
if (ret != QM_QOS_BDF_PARAM_NUM) {
pci_err(qm->pdev, "input pci bdf value is error!\n");
ret = -EINVAL;
goto err_get_status;
}
fun_index = device * 8 + function;
ret = qm_func_shaper_enable(qm, fun_index, val);
if (ret) {
pci_err(qm->pdev, "failed to enable function shaper!\n");
ret = -EINVAL;
goto err_get_status;
}
ret = count;
err_get_status:
clear_bit(QM_RESETTING, &qm->misc_ctl);
return ret;
}
static const struct file_operations qm_algqos_fops = {
.owner = THIS_MODULE,
.open = simple_open,
.write = qm_algqos_write,
};
/**
* hisi_qm_set_algqos_init() - Initialize function qos debugfs files.
* @qm: The qm for which we want to add debugfs files.
*
* Create function qos debugfs files.
*/
static void hisi_qm_set_algqos_init(struct hisi_qm *qm)
{
if (qm->fun_type == QM_HW_PF)
debugfs_create_file("alg_qos", 0644, qm->debug.debug_root,
qm, &qm_algqos_fops);
else
debugfs_create_file("alg_qos", 0444, qm->debug.debug_root,
qm, &qm_algqos_fops);
}
/**
* hisi_qm_sriov_enable() - enable virtual functions
* @pdev: the PCIe device
......@@ -3896,6 +4186,7 @@ EXPORT_SYMBOL_GPL(hisi_qm_sriov_enable);
int hisi_qm_sriov_disable(struct pci_dev *pdev, bool is_frozen)
{
struct hisi_qm *qm = pci_get_drvdata(pdev);
int total_vfs = pci_sriov_get_totalvfs(qm->pdev);
if (pci_vfs_assigned(pdev)) {
pci_err(pdev, "Failed to disable VFs as VFs are assigned!\n");
......@@ -3909,6 +4200,9 @@ int hisi_qm_sriov_disable(struct pci_dev *pdev, bool is_frozen)
}
pci_disable_sriov(pdev);
/* clear vf function shaper configure array */
memset(qm->factor + 1, 0, sizeof(struct qm_shaper_factor) * total_vfs);
return qm_clear_vft_config(qm);
}
EXPORT_SYMBOL_GPL(hisi_qm_sriov_disable);
......
......@@ -76,6 +76,9 @@
#define QM_Q_DEPTH 1024
#define QM_MIN_QNUM 2
#define HISI_ACC_SGL_SGE_NR_MAX 255
#define QM_SHAPER_CFG 0x100164
#define QM_SHAPER_ENABLE BIT(30)
#define QM_SHAPER_TYPE1_OFFSET 10
/* page number for queue file region */
#define QM_DOORBELL_PAGE_NR 1
......@@ -148,6 +151,14 @@ struct qm_debug {
struct debugfs_file files[DEBUG_FILE_NUM];
};
struct qm_shaper_factor {
u32 func_qos;
u64 cir_b;
u64 cir_u;
u64 cir_s;
u64 cbs_s;
};
struct qm_dma {
void *va;
dma_addr_t dma;
......@@ -262,6 +273,9 @@ struct hisi_qm {
resource_size_t db_phys_base;
struct uacce_device *uacce;
int mode;
struct qm_shaper_factor *factor;
u32 mb_qos;
u32 type_rate;
};
struct hisi_qp_status {
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册