crypto: hisilicon/qm - supports to inquiry each function's QoS
authorKai Ye <yekai13@huawei.com>
Fri, 11 Jun 2021 09:06:47 +0000 (17:06 +0800)
committerHerbert Xu <herbert@gondor.apana.org.au>
Thu, 17 Jun 2021 07:07:32 +0000 (15:07 +0800)
1. The ACC driver supports to inquiry each function's QoS in the Host
and VM. The driver supports reading QoS by the device debug SysFS
attribute file "alg_qos", like "cat alg_qos".
2. Modify the communication process between pf and vf as needed.

Signed-off-by: Kai Ye <yekai13@huawei.com>
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
drivers/crypto/hisilicon/qm.c

index 735c8b0..5807094 100644 (file)
@@ -51,6 +51,7 @@
 #define QM_MB_CMD_DATA_ADDR_L          0x304
 #define QM_MB_CMD_DATA_ADDR_H          0x308
 #define QM_MB_PING_ALL_VFS             0xffff
+#define QM_MB_CMD_DATA_SHIFT           32
 #define QM_MB_CMD_DATA_MASK            GENMASK(31, 0)
 
 /* sqc shift */
 
 /* interfunction communication */
 #define QM_IFC_READY_STATUS            0x100128
+#define QM_IFC_C_STS_M                 0x10012C
 #define QM_IFC_INT_SET_P               0x100130
 #define QM_IFC_INT_CFG                 0x100134
 #define QM_IFC_INT_SOURCE_P            0x100138
 #define QM_SHAPER_CBS_B                        1
 #define QM_SHAPER_CBS_S                        16
 #define QM_SHAPER_VFT_OFFSET           6
+#define WAIT_FOR_QOS_VF                        100
 #define QM_QOS_MIN_ERROR_RATE          5
 #define QM_QOS_TYPICAL_NUM             8
 #define QM_SHAPER_MIN_CBS_S            8
@@ -328,6 +331,8 @@ enum qm_mb_cmd {
        QM_VF_PREPARE_FAIL,
        QM_VF_START_DONE,
        QM_VF_START_FAIL,
+       QM_PF_SET_QOS,
+       QM_VF_GET_QOS,
 };
 
 struct qm_cqe {
@@ -2124,7 +2129,7 @@ static void qm_trigger_vf_interrupt(struct hisi_qm *qm, u32 fun_num)
        u32 val;
 
        val = readl(qm->io_base + QM_IFC_INT_CFG);
-       val |= ~QM_IFC_SEND_ALL_VFS;
+       val &= ~QM_IFC_SEND_ALL_VFS;
        val |= fun_num;
        writel(val, qm->io_base + QM_IFC_INT_CFG);
 
@@ -3926,6 +3931,139 @@ static int qm_func_shaper_enable(struct hisi_qm *qm, u32 fun_index, u32 qos)
        return 0;
 }
 
+static u32 qm_get_shaper_vft_qos(struct hisi_qm *qm, u32 fun_index)
+{
+       u64 cir_u = 0, cir_b = 0, cir_s = 0;
+       u64 shaper_vft, ir_calc, ir;
+       unsigned int val;
+       u32 error_rate;
+       int ret;
+
+       ret = readl_relaxed_poll_timeout(qm->io_base + QM_VFT_CFG_RDY, val,
+                                        val & BIT(0), POLL_PERIOD,
+                                        POLL_TIMEOUT);
+       if (ret)
+               return 0;
+
+       writel(0x1, qm->io_base + QM_VFT_CFG_OP_WR);
+       writel(SHAPER_VFT, qm->io_base + QM_VFT_CFG_TYPE);
+       writel(fun_index, qm->io_base + QM_VFT_CFG);
+
+       writel(0x0, qm->io_base + QM_VFT_CFG_RDY);
+       writel(0x1, qm->io_base + QM_VFT_CFG_OP_ENABLE);
+
+       ret = readl_relaxed_poll_timeout(qm->io_base + QM_VFT_CFG_RDY, val,
+                                        val & BIT(0), POLL_PERIOD,
+                                        POLL_TIMEOUT);
+       if (ret)
+               return 0;
+
+       shaper_vft = readl(qm->io_base + QM_VFT_CFG_DATA_L) |
+                 ((u64)readl(qm->io_base + QM_VFT_CFG_DATA_H) << 32);
+
+       cir_b = shaper_vft & QM_SHAPER_CIR_B_MASK;
+       cir_u = shaper_vft & QM_SHAPER_CIR_U_MASK;
+       cir_u = cir_u >> QM_SHAPER_FACTOR_CIR_U_SHIFT;
+
+       cir_s = shaper_vft & QM_SHAPER_CIR_S_MASK;
+       cir_s = cir_s >> QM_SHAPER_FACTOR_CIR_S_SHIFT;
+
+       ir_calc = acc_shaper_para_calc(cir_b, cir_u, cir_s);
+
+       ir = qm->factor[fun_index].func_qos * QM_QOS_RATE;
+
+       error_rate = QM_QOS_EXPAND_RATE * (u32)abs(ir_calc - ir) / ir;
+       if (error_rate > QM_QOS_MIN_ERROR_RATE) {
+               pci_err(qm->pdev, "error_rate: %u, get function qos is error!\n", error_rate);
+               return 0;
+       }
+
+       return ir;
+}
+
+static void qm_vf_get_qos(struct hisi_qm *qm, u32 fun_num)
+{
+       struct device *dev = &qm->pdev->dev;
+       u64 mb_cmd;
+       u32 qos;
+       int ret;
+
+       qos = qm_get_shaper_vft_qos(qm, fun_num);
+       if (!qos) {
+               dev_err(dev, "function(%u) failed to get qos by PF!\n", fun_num);
+               return;
+       }
+
+       mb_cmd = QM_PF_SET_QOS | (u64)qos << QM_MB_CMD_DATA_SHIFT;
+       ret = qm_ping_single_vf(qm, mb_cmd, fun_num);
+       if (ret)
+               dev_err(dev, "failed to send cmd to VF(%u)!\n", fun_num);
+}
+
+static int qm_vf_read_qos(struct hisi_qm *qm)
+{
+       int cnt = 0;
+       int ret;
+
+       /* reset mailbox qos val */
+       qm->mb_qos = 0;
+
+       /* vf ping pf to get function qos */
+       if (qm->ops->ping_pf) {
+               ret = qm->ops->ping_pf(qm, QM_VF_GET_QOS);
+               if (ret) {
+                       pci_err(qm->pdev, "failed to send cmd to PF to get qos!\n");
+                       return ret;
+               }
+       }
+
+       while (true) {
+               msleep(QM_WAIT_DST_ACK);
+               if (qm->mb_qos)
+                       break;
+
+               if (++cnt > QM_MAX_VF_WAIT_COUNT) {
+                       pci_err(qm->pdev, "PF ping VF timeout!\n");
+                       return  -ETIMEDOUT;
+               }
+       }
+
+       return ret;
+}
+
+static ssize_t qm_algqos_read(struct file *filp, char __user *buf,
+                              size_t count, loff_t *pos)
+{
+       struct hisi_qm *qm = filp->private_data;
+       char tbuf[QM_DBG_READ_LEN];
+       u32 qos_val, ir;
+       int ret;
+
+       /* 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, read alg qos failed!\n");
+               return  -EAGAIN;
+       }
+
+       if (qm->fun_type == QM_HW_PF) {
+               ir = qm_get_shaper_vft_qos(qm, 0);
+       } else {
+               ret = qm_vf_read_qos(qm);
+               if (ret)
+                       goto err_get_status;
+               ir = qm->mb_qos;
+       }
+
+       qos_val = ir / QM_QOS_RATE;
+       ret = scnprintf(tbuf, QM_DBG_READ_LEN, "%u\n", qos_val);
+
+       ret =  simple_read_from_buffer(buf, count, pos, tbuf, ret);
+
+err_get_status:
+       clear_bit(QM_RESETTING, &qm->misc_ctl);
+       return ret;
+}
+
 static ssize_t qm_qos_value_init(const char *buf, unsigned long *val)
 {
        int buflen = strlen(buf);
@@ -4020,6 +4158,7 @@ err_get_status:
 static const struct file_operations qm_algqos_fops = {
        .owner = THIS_MODULE,
        .open = simple_open,
+       .read = qm_algqos_read,
        .write = qm_algqos_write,
 };
 
@@ -5129,10 +5268,8 @@ err_get_status:
        qm_reset_bit_clear(qm);
 }
 
-static void qm_cmd_process(struct work_struct *cmd_process)
+static void qm_handle_cmd_msg(struct hisi_qm *qm, u32 fun_num)
 {
-       struct hisi_qm *qm = container_of(cmd_process,
-                                       struct hisi_qm, cmd_process);
        struct device *dev = &qm->pdev->dev;
        u64 msg;
        u32 cmd;
@@ -5142,8 +5279,8 @@ static void qm_cmd_process(struct work_struct *cmd_process)
         * Get the msg from source by sending mailbox. Whether message is got
         * successfully, destination needs to ack source by clearing the interrupt.
         */
-       ret = qm_get_mb_cmd(qm, &msg, 0);
-       qm_clear_cmd_interrupt(qm, 0);
+       ret = qm_get_mb_cmd(qm, &msg, fun_num);
+       qm_clear_cmd_interrupt(qm, BIT(fun_num));
        if (ret) {
                dev_err(dev, "failed to get msg from source!\n");
                return;
@@ -5157,12 +5294,42 @@ static void qm_cmd_process(struct work_struct *cmd_process)
        case QM_PF_SRST_PREPARE:
                qm_pf_reset_vf_process(qm, QM_SOFT_RESET);
                break;
+       case QM_VF_GET_QOS:
+               qm_vf_get_qos(qm, fun_num);
+               break;
+       case QM_PF_SET_QOS:
+               qm->mb_qos = msg >> QM_MB_CMD_DATA_SHIFT;
+               break;
        default:
-               dev_err(dev, "unsupported cmd %u sent by PF!\n", cmd);
+               dev_err(dev, "unsupported cmd %u sent by function(%u)!\n", cmd, fun_num);
                break;
        }
 }
 
+static void qm_cmd_process(struct work_struct *cmd_process)
+{
+       struct hisi_qm *qm = container_of(cmd_process,
+                                       struct hisi_qm, cmd_process);
+       u32 vfs_num = qm->vfs_num;
+       u64 val;
+       u32 i;
+
+       if (qm->fun_type == QM_HW_PF) {
+               val = readq(qm->io_base + QM_IFC_INT_SOURCE_P);
+               if (!val)
+                       return;
+
+               for (i = 1; i <= vfs_num; i++) {
+                       if (val & BIT(i))
+                               qm_handle_cmd_msg(qm, i);
+               }
+
+               return;
+       }
+
+       qm_handle_cmd_msg(qm, 0);
+}
+
 /**
  * hisi_qm_alg_register() - Register alg to crypto and add qm to qm_list.
  * @qm: The qm needs add.